diff --git a/.htaccess b/.htaccess new file mode 100644 index 000000000..5e8e3d2e2 --- /dev/null +++ b/.htaccess @@ -0,0 +1,13 @@ + +# Caching + +# 1 week for images, videos + +Header set Cache-Control "public, max-age=604800, no-transform" + + + +Header set Cache-Control "public, max-age=120, must-revalidate" + + + \ No newline at end of file diff --git a/.preview/404.png b/.preview/404.png new file mode 100644 index 000000000..32389ed11 Binary files /dev/null and b/.preview/404.png differ diff --git a/.preview/ configuration.png b/.preview/ configuration.png new file mode 100644 index 000000000..5744309c1 Binary files /dev/null and b/.preview/ configuration.png differ diff --git a/.preview/@serializable and other decorators.png b/.preview/@serializable and other decorators.png new file mode 100644 index 000000000..16ea6afa2 Binary files /dev/null and b/.preview/@serializable and other decorators.png differ diff --git a/.preview/additional modules.png b/.preview/additional modules.png new file mode 100644 index 000000000..c337c2f91 Binary files /dev/null and b/.preview/additional modules.png differ diff --git a/.preview/automatic component generation.png b/.preview/automatic component generation.png new file mode 100644 index 000000000..e3087aedc Binary files /dev/null and b/.preview/automatic component generation.png differ diff --git a/.preview/backlog mermaid.png b/.preview/backlog mermaid.png new file mode 100644 index 000000000..fba46cab1 Binary files /dev/null and b/.preview/backlog mermaid.png differ diff --git a/.preview/backlog.png b/.preview/backlog.png new file mode 100644 index 000000000..3fdff728d Binary files /dev/null and b/.preview/backlog.png differ diff --git a/.preview/bike configurator.png b/.preview/bike configurator.png new file mode 100644 index 000000000..cfba5f434 Binary files /dev/null and b/.preview/bike configurator.png differ diff --git a/.preview/castle builder.png b/.preview/castle builder.png new file mode 100644 index 000000000..09382a4c8 Binary files /dev/null and b/.preview/castle builder.png differ diff --git a/.preview/community: contributions.png b/.preview/community: contributions.png new file mode 100644 index 000000000..37b6d74db Binary files /dev/null and b/.preview/community: contributions.png differ diff --git a/.preview/contributions: ericcraft mh.png b/.preview/contributions: ericcraft mh.png new file mode 100644 index 000000000..f81ccf6c0 Binary files /dev/null and b/.preview/contributions: ericcraft mh.png differ diff --git a/.preview/contributions: kipash.png b/.preview/contributions: kipash.png new file mode 100644 index 000000000..0782c1118 Binary files /dev/null and b/.preview/contributions: kipash.png differ diff --git a/.preview/contributions: krisrok.png b/.preview/contributions: krisrok.png new file mode 100644 index 000000000..6d75491af Binary files /dev/null and b/.preview/contributions: krisrok.png differ diff --git a/.preview/contributions: llllkatjallll.png b/.preview/contributions: llllkatjallll.png new file mode 100644 index 000000000..33ec506a5 Binary files /dev/null and b/.preview/contributions: llllkatjallll.png differ diff --git a/.preview/contributions: marwie.png b/.preview/contributions: marwie.png new file mode 100644 index 000000000..d8b49c495 Binary files /dev/null and b/.preview/contributions: marwie.png differ diff --git a/.preview/contributions: robyer1.png b/.preview/contributions: robyer1.png new file mode 100644 index 000000000..053cd23f4 Binary files /dev/null and b/.preview/contributions: robyer1.png differ diff --git a/.preview/contributions: web3kev.png b/.preview/contributions: web3kev.png new file mode 100644 index 000000000..648e2f90c Binary files /dev/null and b/.preview/contributions: web3kev.png differ diff --git a/.preview/creating and using components.png b/.preview/creating and using components.png new file mode 100644 index 000000000..e8c6a7e67 Binary files /dev/null and b/.preview/creating and using components.png differ diff --git a/.preview/custom integrations.png b/.preview/custom integrations.png new file mode 100644 index 000000000..6bdb8385d Binary files /dev/null and b/.preview/custom integrations.png differ diff --git a/.preview/deployment and optimization.png b/.preview/deployment and optimization.png new file mode 100644 index 000000000..19915bf2f Binary files /dev/null and b/.preview/deployment and optimization.png differ diff --git a/.preview/embedding.png b/.preview/embedding.png new file mode 100644 index 000000000..c4f2e9b9d Binary files /dev/null and b/.preview/embedding.png differ diff --git a/.preview/ericcraft mh: quicklook vertical image tracker.png b/.preview/ericcraft mh: quicklook vertical image tracker.png new file mode 100644 index 000000000..ed4f52bd3 Binary files /dev/null and b/.preview/ericcraft mh: quicklook vertical image tracker.png differ diff --git a/.preview/everywhere actions.png b/.preview/everywhere actions.png new file mode 100644 index 000000000..127656e3f Binary files /dev/null and b/.preview/everywhere actions.png differ diff --git a/.preview/examples.png b/.preview/examples.png new file mode 100644 index 000000000..20508fdf9 Binary files /dev/null and b/.preview/examples.png differ diff --git a/.preview/exporting assets to gltf.png b/.preview/exporting assets to gltf.png new file mode 100644 index 000000000..008f201fc Binary files /dev/null and b/.preview/exporting assets to gltf.png differ diff --git a/.preview/features overview.png b/.preview/features overview.png new file mode 100644 index 000000000..7bfd49fbd Binary files /dev/null and b/.preview/features overview.png differ diff --git a/.preview/frameworks, bundlers, html.png b/.preview/frameworks, bundlers, html.png new file mode 100644 index 000000000..985381dca Binary files /dev/null and b/.preview/frameworks, bundlers, html.png differ diff --git a/.preview/getting started & installation.png b/.preview/getting started & installation.png new file mode 100644 index 000000000..230d1c3e1 Binary files /dev/null and b/.preview/getting started & installation.png differ diff --git a/.preview/getting started.png b/.preview/getting started.png new file mode 100644 index 000000000..f401faf1d Binary files /dev/null and b/.preview/getting started.png differ diff --git a/.preview/how to debug.png b/.preview/how to debug.png new file mode 100644 index 000000000..1f9f0d8e9 Binary files /dev/null and b/.preview/how to debug.png differ diff --git a/.preview/kipash: calculate pointer world position.png b/.preview/kipash: calculate pointer world position.png new file mode 100644 index 000000000..b72efe461 Binary files /dev/null and b/.preview/kipash: calculate pointer world position.png differ diff --git a/.preview/krisrok: always open in specific browser.png b/.preview/krisrok: always open in specific browser.png new file mode 100644 index 000000000..276a595d6 Binary files /dev/null and b/.preview/krisrok: always open in specific browser.png differ diff --git a/.preview/llllkatjallll: custom vr button that appears only on headsets and not on mobile phones.png b/.preview/llllkatjallll: custom vr button that appears only on headsets and not on mobile phones.png new file mode 100644 index 000000000..8a2a19939 Binary files /dev/null and b/.preview/llllkatjallll: custom vr button that appears only on headsets and not on mobile phones.png differ diff --git a/.preview/llllkatjallll: set fallback material for usdz exporter.png b/.preview/llllkatjallll: set fallback material for usdz exporter.png new file mode 100644 index 000000000..6bfe0d653 Binary files /dev/null and b/.preview/llllkatjallll: set fallback material for usdz exporter.png differ diff --git a/.preview/marwie: camera video background.png b/.preview/marwie: camera video background.png new file mode 100644 index 000000000..346140a1b Binary files /dev/null and b/.preview/marwie: camera video background.png differ diff --git a/.preview/marwie: code contribution example.png b/.preview/marwie: code contribution example.png new file mode 100644 index 000000000..11bcffda6 Binary files /dev/null and b/.preview/marwie: code contribution example.png differ diff --git a/.preview/marwie: control a timeline by scroll.png b/.preview/marwie: control a timeline by scroll.png new file mode 100644 index 000000000..123a11834 Binary files /dev/null and b/.preview/marwie: control a timeline by scroll.png differ diff --git a/.preview/marwie: everywhere action emphasize on click.png b/.preview/marwie: everywhere action emphasize on click.png new file mode 100644 index 000000000..869a3abf8 Binary files /dev/null and b/.preview/marwie: everywhere action emphasize on click.png differ diff --git a/.preview/marwie: usdz hide object on start.png b/.preview/marwie: usdz hide object on start.png new file mode 100644 index 000000000..95017c717 Binary files /dev/null and b/.preview/marwie: usdz hide object on start.png differ diff --git a/.preview/mercedes benz showcase.png b/.preview/mercedes benz showcase.png new file mode 100644 index 000000000..7bf74204c Binary files /dev/null and b/.preview/mercedes benz showcase.png differ diff --git a/.preview/meta test.png b/.preview/meta test.png new file mode 100644 index 000000000..723b0d97e Binary files /dev/null and b/.preview/meta test.png differ diff --git a/.preview/monster hands.png b/.preview/monster hands.png new file mode 100644 index 000000000..83122ee22 Binary files /dev/null and b/.preview/monster hands.png differ diff --git a/.preview/needle core components.png b/.preview/needle core components.png new file mode 100644 index 000000000..72c5237db Binary files /dev/null and b/.preview/needle core components.png differ diff --git a/.preview/needle engine.png b/.preview/needle engine.png new file mode 100644 index 000000000..47b2ec5e7 Binary files /dev/null and b/.preview/needle engine.png differ diff --git a/.preview/needle.png b/.preview/needle.png new file mode 100644 index 000000000..f4844c2f0 Binary files /dev/null and b/.preview/needle.png differ diff --git a/.preview/networking.png b/.preview/networking.png new file mode 100644 index 000000000..635f2027b Binary files /dev/null and b/.preview/networking.png differ diff --git a/.preview/robyer1: ar move scale rotate controls for needle on mobile.png b/.preview/robyer1: ar move scale rotate controls for needle on mobile.png new file mode 100644 index 000000000..70eead008 Binary files /dev/null and b/.preview/robyer1: ar move scale rotate controls for needle on mobile.png differ diff --git a/.preview/robyer1: microphone access in a browser window and streamed playback.png b/.preview/robyer1: microphone access in a browser window and streamed playback.png new file mode 100644 index 000000000..981057835 Binary files /dev/null and b/.preview/robyer1: microphone access in a browser window and streamed playback.png differ diff --git a/.preview/samples projects.png b/.preview/samples projects.png new file mode 100644 index 000000000..f8fab5b64 Binary files /dev/null and b/.preview/samples projects.png differ diff --git a/.preview/scripting examples.png b/.preview/scripting examples.png new file mode 100644 index 000000000..7aa11f85a Binary files /dev/null and b/.preview/scripting examples.png differ diff --git a/.preview/scripting in needle engine.png b/.preview/scripting in needle engine.png new file mode 100644 index 000000000..a7243c650 Binary files /dev/null and b/.preview/scripting in needle engine.png differ diff --git a/.preview/scripting introduction for unity developers.png b/.preview/scripting introduction for unity developers.png new file mode 100644 index 000000000..31c979a93 Binary files /dev/null and b/.preview/scripting introduction for unity developers.png differ diff --git a/.preview/summary.png b/.preview/summary.png new file mode 100644 index 000000000..8f155ecc4 Binary files /dev/null and b/.preview/summary.png differ diff --git a/.preview/support.png b/.preview/support.png new file mode 100644 index 000000000..c8fa464b6 Binary files /dev/null and b/.preview/support.png differ diff --git a/.preview/technical overview.png b/.preview/technical overview.png new file mode 100644 index 000000000..3a72c3749 Binary files /dev/null and b/.preview/technical overview.png differ diff --git a/.preview/testimonials.png b/.preview/testimonials.png new file mode 100644 index 000000000..eb3decd22 Binary files /dev/null and b/.preview/testimonials.png differ diff --git a/.preview/testing on local devices.png b/.preview/testing on local devices.png new file mode 100644 index 000000000..3a4af0fcf Binary files /dev/null and b/.preview/testing on local devices.png differ diff --git a/.preview/three.png b/.preview/three.png new file mode 100644 index 000000000..eac4d7b3b Binary files /dev/null and b/.preview/three.png differ diff --git a/.preview/tower defense.png b/.preview/tower defense.png new file mode 100644 index 000000000..e58017856 Binary files /dev/null and b/.preview/tower defense.png differ diff --git a/.preview/unity: editor sync.png b/.preview/unity: editor sync.png new file mode 100644 index 000000000..bc2a314f3 Binary files /dev/null and b/.preview/unity: editor sync.png differ diff --git a/.preview/using needle engine directly from html.png b/.preview/using needle engine directly from html.png new file mode 100644 index 000000000..1c909c026 Binary files /dev/null and b/.preview/using needle engine directly from html.png differ diff --git a/.preview/vision.png b/.preview/vision.png new file mode 100644 index 000000000..02dd187be Binary files /dev/null and b/.preview/vision.png differ diff --git a/.preview/vr & ar.png b/.preview/vr & ar.png new file mode 100644 index 000000000..bb81b93b9 Binary files /dev/null and b/.preview/vr & ar.png differ diff --git a/.preview/web3kev: network instantiation of multiple objects.png b/.preview/web3kev: network instantiation of multiple objects.png new file mode 100644 index 000000000..0747bd934 Binary files /dev/null and b/.preview/web3kev: network instantiation of multiple objects.png differ diff --git a/.preview/web3kev: squeeze to scale object or world in vr.png b/.preview/web3kev: squeeze to scale object or world in vr.png new file mode 100644 index 000000000..24977d090 Binary files /dev/null and b/.preview/web3kev: squeeze to scale object or world in vr.png differ diff --git a/.preview/web3kev: vertical move in vr using the right joystick quest.png b/.preview/web3kev: vertical move in vr using the right joystick quest.png new file mode 100644 index 000000000..28a69a851 Binary files /dev/null and b/.preview/web3kev: vertical move in vr using the right joystick quest.png differ diff --git a/404.html b/404.html new file mode 100644 index 000000000..bc454297a --- /dev/null +++ b/404.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

404

Gosh! You found a ๐ŸŒต glitch
Take me home
+ + + diff --git a/SUMMARY.html b/SUMMARY.html new file mode 100644 index 000000000..7d2188684 --- /dev/null +++ b/SUMMARY.html @@ -0,0 +1,43 @@ + + + + + + + + + Get Started | Needle Engine Documentation + + + + + +
+ + + diff --git a/android-chrome-144x144.png b/android-chrome-144x144.png new file mode 100644 index 000000000..9680622fd Binary files /dev/null and b/android-chrome-144x144.png differ diff --git a/assets/404.html-DQk9SM3x.js b/assets/404.html-DQk9SM3x.js new file mode 100644 index 000000000..72bf8f901 --- /dev/null +++ b/assets/404.html-DQk9SM3x.js @@ -0,0 +1 @@ +import{_ as t,o as n,c as o,a}from"./app-CRZRGfEE.js";const l={};function r(s,e){return n(),o("div",null,e[0]||(e[0]=[a("p",null,"404 Not Found",-1)]))}const i=t(l,[["render",r],["__file","404.html.vue"]]),d=JSON.parse('{"path":"/404.html","title":"","lang":"en-US","frontmatter":{"layout":"NotFound","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/404.png"}],["meta",{"name":"og:description","content":"d"}]],"description":"d"},"headers":[],"git":{},"filePathRelative":null}');export{i as comp,d as data}; diff --git a/assets/NoDownloadYet-CimAPJue.js b/assets/NoDownloadYet-CimAPJue.js new file mode 100644 index 000000000..f486fab3b --- /dev/null +++ b/assets/NoDownloadYet-CimAPJue.js @@ -0,0 +1 @@ +import{_ as a,f as o,g as t}from"./app-CRZRGfEE.js";const n={methods:{checkQueryParams:s}};function s(){return typeof window>"u"?!1:new URLSearchParams(window.location.search).has("dl")}function c(e,d,u,f,l,r){return r.checkQueryParams()?t("",!0):o(e.$slots,"default",{key:0})}const i=a(n,[["render",c],["__file","NoDownloadYet.vue"]]);export{i as default}; diff --git a/assets/SUMMARY.html-o_nWAvKL.js b/assets/SUMMARY.html-o_nWAvKL.js new file mode 100644 index 000000000..f36e47898 --- /dev/null +++ b/assets/SUMMARY.html-o_nWAvKL.js @@ -0,0 +1 @@ +import{_ as i,r as a,o as s,c as d,a as t,b as n,w as o,d as r}from"./app-CRZRGfEE.js";const u={};function m(p,e){const l=a("RouteLink");return s(),d("div",null,[e[17]||(e[17]=t("h1",{id:"get-started",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#get-started"},[t("span",null,"Get Started")])],-1)),t("ul",null,[t("li",null,[n(l,{to:"/getting-started/"},{default:o(()=>e[0]||(e[0]=[r("Getting Started โญ")])),_:1}),t("ul",null,[t("li",null,[n(l,{to:"/features-overview.html"},{default:o(()=>e[1]||(e[1]=[r("Feature Overview")])),_:1})]),t("li",null,[n(l,{to:"/export.html"},{default:o(()=>e[2]||(e[2]=[r("Export")])),_:1})]),t("li",null,[n(l,{to:"/project-structure.html"},{default:o(()=>e[3]||(e[3]=[r("Project Structure")])),_:1})]),t("li",null,[n(l,{to:"/xr.html"},{default:o(()=>e[4]||(e[4]=[r("VR and AR")])),_:1})]),t("li",null,[n(l,{to:"/scripting.html"},{default:o(()=>e[5]||(e[5]=[r("Scripting")])),_:1})]),t("li",null,[n(l,{to:"/html.html"},{default:o(()=>e[6]||(e[6]=[r("HTML")])),_:1})]),t("li",null,[n(l,{to:"/deployment.html"},{default:o(()=>e[7]||(e[7]=[r("Deployment")])),_:1})])])])]),e[18]||(e[18]=t("h1",{id:"samples",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#samples"},[t("span",null,"Samples")])],-1)),t("ul",null,[t("li",null,[n(l,{to:"/samples-and-modules.html"},{default:o(()=>e[8]||(e[8]=[r("Samples and Examples")])),_:1}),t("ul",null,[t("li",null,[n(l,{to:"/for-unity-developers.html"},{default:o(()=>e[9]||(e[9]=[r("Tips for Unity Developers")])),_:1})]),t("li",null,[n(l,{to:"/examples.html"},{default:o(()=>e[10]||(e[10]=[r("Showcase")])),_:1})]),t("li",null,[n(l,{to:"/samples-and-modules.html"},{default:o(()=>e[11]||(e[11]=[r("Project Samples, Examples and Modules")])),_:1})]),t("li",null,[n(l,{to:"/faq.html"},{default:o(()=>e[12]||(e[12]=[r("FAQ")])),_:1})])])])]),e[19]||(e[19]=t("h1",{id:"dive-deeper",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#dive-deeper"},[t("span",null,"Dive Deeper ๐Ÿ ")])],-1)),t("ul",null,[t("li",null,[n(l,{to:"/vision.html"},{default:o(()=>e[13]||(e[13]=[r("Our Vision")])),_:1}),t("ul",null,[t("li",null,[n(l,{to:"/technical-overview.html"},{default:o(()=>e[14]||(e[14]=[r("Technical Overview")])),_:1})]),t("li",null,[n(l,{to:"/component-reference.html"},{default:o(()=>e[15]||(e[15]=[r("Component Reference")])),_:1})]),t("li",null,[n(l,{to:"/debugging.html"},{default:o(()=>e[16]||(e[16]=[r("Debugging")])),_:1})])])])])])}const g=i(u,[["render",m],["__file","SUMMARY.html.vue"]]),b=JSON.parse('{"path":"/SUMMARY.html","title":"Get Started","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/summary.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{"updatedTime":1726487589000},"filePathRelative":"SUMMARY.md"}');export{g as comp,b as data}; diff --git a/assets/action-Dm_y7Sbx.js b/assets/action-Dm_y7Sbx.js new file mode 100644 index 000000000..f0ec6be40 --- /dev/null +++ b/assets/action-Dm_y7Sbx.js @@ -0,0 +1 @@ +import{_ as o,o as t,c as s,f as a,t as r,g as c}from"./app-CRZRGfEE.js";const i={props:{href:String,subtitle:String}},l=["href"],_={key:0,class:"subtitle"};function f(n,d,e,u,h,p){return t(),s("a",{class:"action no-external-link-icon",href:e.href},[a(n.$slots,"default",{},void 0,!0),e.subtitle?(t(),s("span",_,r(e.subtitle),1)):c("",!0)],8,l)}const b=o(i,[["render",f],["__scopeId","data-v-705b9710"],["__file","action.vue"]]);export{b as default}; diff --git a/assets/actiongroup-gFGdAuKO.js b/assets/actiongroup-gFGdAuKO.js new file mode 100644 index 000000000..014e1535a --- /dev/null +++ b/assets/actiongroup-gFGdAuKO.js @@ -0,0 +1 @@ +import{_ as e,o as t,c as s,f as c}from"./app-CRZRGfEE.js";const r={},a={class:"actiongroup"};function n(o,_,p,i,f,l){return t(),s("div",a,[c(o.$slots,"default")])}const d=e(r,[["render",n],["__file","actiongroup.vue"]]);export{d as default}; diff --git a/assets/always-open-in-specific-browser.html-Cboldk4x.js b/assets/always-open-in-specific-browser.html-Cboldk4x.js new file mode 100644 index 000000000..8ba25a75b --- /dev/null +++ b/assets/always-open-in-specific-browser.html-Cboldk4x.js @@ -0,0 +1,31 @@ +import{_ as n,r as t,o as l,c as e,a as i,b as h,e as k}from"./app-CRZRGfEE.js";const p={};function r(o,s){const a=t("contribution-header");return l(),e("div",null,[s[0]||(s[0]=i("p",null,[i("a",{href:"/docs/community/contributions"},"Overview")],-1)),h(a,{url:"https://github.com/krisrok",author:"krisrok",page:"/docs/community/contributions/krisrok",profileImage:"https://avatars.githubusercontent.com/u/3404365?s=100&u=7025bf7e83b4a3cd72dc2cae9cec729080ee8970&v=4",githubUrl:"https://github.com/needle-tools/needle-engine-support/discussions/178",title:"Always open in specific browser",gradient:"True"}),s[1]||(s[1]=k(`

Add this class to your project to always open with Chrome instead of your default browser (Firefox in my case) when you click "Play" or "Start Server". Note: This is an editor class and should either be put into an editor-only assembly or wrapped in #if UNITY_EDITOR and #endif.

using System.Diagnostics;
+using UnityEditor;
+using UnityEngine;
+using Needle.Engine;
+
+[InitializeOnLoad]
+public static class CustomBrowserOpen
+{
+    static CustomBrowserOpen()
+    {
+        Init();
+    }
+
+    [RuntimeInitializeOnLoadMethod]
+    static void Init()
+    {
+        ActionsBrowser.BeforeOpen += ActionsBrowser_BeforeOpen;
+    }
+
+    private static void ActionsBrowser_BeforeOpen(ActionsBrowser.OpenBrowserArguments args)
+    {
+        args.PreventDefault = true;
+        string processArgs = args.Url;
+        var psi = new ProcessStartInfo
+        {
+            FileName = "chrome.exe",
+            Arguments = processArgs
+        };
+        Process.Start(psi);
+    }
+}
`,2))])}const c=n(p,[["render",r],["__file","always-open-in-specific-browser.html.vue"]]),y=JSON.parse('{"path":"/community/contributions/krisrok/always-open-in-specific-browser","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/krisrok: always open in specific browser.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{c as comp,y as data}; diff --git a/assets/app-CRZRGfEE.js b/assets/app-CRZRGfEE.js new file mode 100644 index 000000000..304257c4f --- /dev/null +++ b/assets/app-CRZRGfEE.js @@ -0,0 +1,28 @@ +const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/deployment.html-C3wlSpNe.js","assets/texture-compression-BuEaeBZn.js","assets/ktx-env-variable-DxwKzzNo.js","assets/faq.html-B6pZlv9Y.js","assets/html.html-DP7Dz9Ne.js","assets/custom-loading-style-s1K1my2z.js","assets/index.html-Ci232zr-.js","assets/needle-engine-attributes.html-Dizdapts.js"])))=>i.map(i=>d[i]); +/** +* @vue/shared v3.5.8 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**//*! #__NO_SIDE_EFFECTS__ */function Ko(e){const t=Object.create(null);for(const n of e.split(","))t[n]=1;return n=>n in t}const _e={},bn=[],vt=()=>{},Ua=()=>!1,or=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&(e.charCodeAt(2)>122||e.charCodeAt(2)<97),Go=e=>e.startsWith("onUpdate:"),Re=Object.assign,qo=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},Wa=Object.prototype.hasOwnProperty,ue=(e,t)=>Wa.call(e,t),te=Array.isArray,yn=e=>Gr(e)==="[object Map]",Bi=e=>Gr(e)==="[object Set]",oe=e=>typeof e=="function",Te=e=>typeof e=="string",Ut=e=>typeof e=="symbol",Ee=e=>e!==null&&typeof e=="object",Fi=e=>(Ee(e)||oe(e))&&oe(e.then)&&oe(e.catch),zi=Object.prototype.toString,Gr=e=>zi.call(e),Ka=e=>Gr(e).slice(8,-1),Ui=e=>Gr(e)==="[object Object]",Yo=e=>Te(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,En=Ko(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),qr=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},Ga=/-(\w)/g,rt=qr(e=>e.replace(Ga,(t,n)=>n?n.toUpperCase():"")),qa=/\B([A-Z])/g,Wt=qr(e=>e.replace(qa,"-$1").toLowerCase()),sr=qr(e=>e.charAt(0).toUpperCase()+e.slice(1)),ao=qr(e=>e?`on${sr(e)}`:""),jt=(e,t)=>!Object.is(e,t),co=(e,...t)=>{for(let n=0;n{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,writable:r,value:n})},Ya=e=>{const t=parseFloat(e);return isNaN(t)?e:t},Ja=e=>{const t=Te(e)?Number(e):NaN;return isNaN(t)?e:t};let Ts;const Ki=()=>Ts||(Ts=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function ir(e){if(te(e)){const t={};for(let n=0;n{if(n){const r=n.split(Xa);r.length>1&&(t[r[0].trim()]=r[1].trim())}}),t}function Qe(e){let t="";if(Te(e))t=e;else if(te(e))for(let n=0;n!!(e&&e.__v_isRef===!0),Le=e=>Te(e)?e:e==null?"":te(e)||Ee(e)&&(e.toString===zi||!oe(e.toString))?qi(e)?Le(e.value):JSON.stringify(e,Yi,2):String(e),Yi=(e,t)=>qi(t)?Yi(e,t.value):yn(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((n,[r,o],s)=>(n[uo(r,s)+" =>"]=o,n),{})}:Bi(t)?{[`Set(${t.size})`]:[...t.values()].map(n=>uo(n))}:Ut(t)?uo(t):Ee(t)&&!te(t)&&!Ui(t)?String(t):t,uo=(e,t="")=>{var n;return Ut(e)?`Symbol(${(n=e.description)!=null?n:t})`:e};/** +* @vue/reactivity v3.5.8 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/let Ge;class rc{constructor(t=!1){this.detached=t,this._active=!0,this.effects=[],this.cleanups=[],this._isPaused=!1,this.parent=Ge,!t&&Ge&&(this.index=(Ge.scopes||(Ge.scopes=[])).push(this)-1)}get active(){return this._active}pause(){if(this._active){this._isPaused=!0;let t,n;if(this.scopes)for(t=0,n=this.scopes.length;t0)return;let e;for(;Bn;){let t=Bn;for(Bn=void 0;t;){const n=t.next;if(t.next=void 0,t.flags&=-9,t.flags&1)try{t.trigger()}catch(r){e||(e=r)}t=n}}if(e)throw e}function el(e){for(let t=e.deps;t;t=t.nextDep)t.version=-1,t.prevActiveLink=t.dep.activeLink,t.dep.activeLink=t}function tl(e,t=!1){let n,r=e.depsTail,o=r;for(;o;){const s=o.prevDep;o.version===-1?(o===r&&(r=s),Xo(o,t),sc(o)):n=o,o.dep.activeLink=o.prevActiveLink,o.prevActiveLink=void 0,o=s}e.deps=n,e.depsTail=r}function ko(e){for(let t=e.deps;t;t=t.nextDep)if(t.dep.version!==t.version||t.dep.computed&&(nl(t.dep.computed)||t.dep.version!==t.version))return!0;return!!e._dirty}function nl(e){if(e.flags&4&&!(e.flags&16)||(e.flags&=-17,e.globalVersion===Kn))return;e.globalVersion=Kn;const t=e.dep;if(e.flags|=2,t.version>0&&!e.isSSR&&e.deps&&!ko(e)){e.flags&=-3;return}const n=ve,r=ct;ve=e,ct=!0;try{el(e);const o=e.fn(e._value);(t.version===0||jt(o,e._value))&&(e._value=o,t.version++)}catch(o){throw t.version++,o}finally{ve=n,ct=r,tl(e,!0),e.flags&=-3}}function Xo(e,t=!1){const{dep:n,prevSub:r,nextSub:o}=e;if(r&&(r.nextSub=o,e.prevSub=void 0),o&&(o.prevSub=r,e.nextSub=void 0),n.subs===e&&(n.subs=r),!n.subs)if(n.computed){n.computed.flags&=-5;for(let s=n.computed.deps;s;s=s.nextDep)Xo(s,!0)}else n.map&&!t&&(n.map.delete(n.key),n.map.size||Gn.delete(n.target))}function sc(e){const{prevDep:t,nextDep:n}=e;t&&(t.nextDep=n,e.prevDep=void 0),n&&(n.prevDep=t,e.nextDep=void 0)}let ct=!0;const rl=[];function Kt(){rl.push(ct),ct=!1}function Gt(){const e=rl.pop();ct=e===void 0?!0:e}function ks(e){const{cleanup:t}=e;if(e.cleanup=void 0,t){const n=ve;ve=void 0;try{t()}finally{ve=n}}}let Kn=0;class ic{constructor(t,n){this.sub=t,this.dep=n,this.version=n.version,this.nextDep=this.prevDep=this.nextSub=this.prevSub=this.prevActiveLink=void 0}}class Yr{constructor(t){this.computed=t,this.version=0,this.activeLink=void 0,this.subs=void 0,this.target=void 0,this.map=void 0,this.key=void 0}track(t){if(!ve||!ct||ve===this.computed)return;let n=this.activeLink;if(n===void 0||n.sub!==ve)n=this.activeLink=new ic(ve,this),ve.deps?(n.prevDep=ve.depsTail,ve.depsTail.nextDep=n,ve.depsTail=n):ve.deps=ve.depsTail=n,ve.flags&4&&ol(n);else if(n.version===-1&&(n.version=this.version,n.nextDep)){const r=n.nextDep;r.prevDep=n.prevDep,n.prevDep&&(n.prevDep.nextDep=r),n.prevDep=ve.depsTail,n.nextDep=void 0,ve.depsTail.nextDep=n,ve.depsTail=n,ve.deps===n&&(ve.deps=r)}return n}trigger(t){this.version++,Kn++,this.notify(t)}notify(t){Jo();try{for(let n=this.subs;n;n=n.prevSub)n.sub.notify()&&n.sub.dep.notify()}finally{Qo()}}}function ol(e){const t=e.dep.computed;if(t&&!e.dep.subs){t.flags|=20;for(let r=t.deps;r;r=r.nextDep)ol(r)}const n=e.dep.subs;n!==e&&(e.prevSub=n,n&&(n.nextSub=e)),e.dep.subs=e}const Gn=new WeakMap,rn=Symbol(""),Ao=Symbol(""),qn=Symbol("");function Ue(e,t,n){if(ct&&ve){let r=Gn.get(e);r||Gn.set(e,r=new Map);let o=r.get(n);o||(r.set(n,o=new Yr),o.target=e,o.map=r,o.key=n),o.track()}}function Tt(e,t,n,r,o,s){const i=Gn.get(e);if(!i){Kn++;return}const l=a=>{a&&a.trigger()};if(Jo(),t==="clear")i.forEach(l);else{const a=te(e),f=a&&Yo(n);if(a&&n==="length"){const u=Number(r);i.forEach((c,p)=>{(p==="length"||p===qn||!Ut(p)&&p>=u)&&l(c)})}else switch(n!==void 0&&l(i.get(n)),f&&l(i.get(qn)),t){case"add":a?f&&l(i.get("length")):(l(i.get(rn)),yn(e)&&l(i.get(Ao)));break;case"delete":a||(l(i.get(rn)),yn(e)&&l(i.get(Ao)));break;case"set":yn(e)&&l(i.get(rn));break}}Qo()}function lc(e,t){var n;return(n=Gn.get(e))==null?void 0:n.get(t)}function pn(e){const t=ce(e);return t===e?t:(Ue(t,"iterate",qn),lt(e)?t:t.map(je))}function Jr(e){return Ue(e=ce(e),"iterate",qn),e}const ac={__proto__:null,[Symbol.iterator](){return po(this,Symbol.iterator,je)},concat(...e){return pn(this).concat(...e.map(t=>te(t)?pn(t):t))},entries(){return po(this,"entries",e=>(e[1]=je(e[1]),e))},every(e,t){return wt(this,"every",e,t,void 0,arguments)},filter(e,t){return wt(this,"filter",e,t,n=>n.map(je),arguments)},find(e,t){return wt(this,"find",e,t,je,arguments)},findIndex(e,t){return wt(this,"findIndex",e,t,void 0,arguments)},findLast(e,t){return wt(this,"findLast",e,t,je,arguments)},findLastIndex(e,t){return wt(this,"findLastIndex",e,t,void 0,arguments)},forEach(e,t){return wt(this,"forEach",e,t,void 0,arguments)},includes(...e){return ho(this,"includes",e)},indexOf(...e){return ho(this,"indexOf",e)},join(e){return pn(this).join(e)},lastIndexOf(...e){return ho(this,"lastIndexOf",e)},map(e,t){return wt(this,"map",e,t,void 0,arguments)},pop(){return Dn(this,"pop")},push(...e){return Dn(this,"push",e)},reduce(e,...t){return As(this,"reduce",e,t)},reduceRight(e,...t){return As(this,"reduceRight",e,t)},shift(){return Dn(this,"shift")},some(e,t){return wt(this,"some",e,t,void 0,arguments)},splice(...e){return Dn(this,"splice",e)},toReversed(){return pn(this).toReversed()},toSorted(e){return pn(this).toSorted(e)},toSpliced(...e){return pn(this).toSpliced(...e)},unshift(...e){return Dn(this,"unshift",e)},values(){return po(this,"values",je)}};function po(e,t,n){const r=Jr(e),o=r[t]();return r!==e&&!lt(e)&&(o._next=o.next,o.next=()=>{const s=o._next();return s.value&&(s.value=n(s.value)),s}),o}const cc=Array.prototype;function wt(e,t,n,r,o,s){const i=Jr(e),l=i!==e&&!lt(e),a=i[t];if(a!==cc[t]){const c=a.apply(e,s);return l?je(c):c}let f=n;i!==e&&(l?f=function(c,p){return n.call(this,je(c),p,e)}:n.length>2&&(f=function(c,p){return n.call(this,c,p,e)}));const u=a.call(i,f,r);return l&&o?o(u):u}function As(e,t,n,r){const o=Jr(e);let s=n;return o!==e&&(lt(e)?n.length>3&&(s=function(i,l,a){return n.call(this,i,l,a,e)}):s=function(i,l,a){return n.call(this,i,je(l),a,e)}),o[t](s,...r)}function ho(e,t,n){const r=ce(e);Ue(r,"iterate",qn);const o=r[t](...n);return(o===-1||o===!1)&&ns(n[0])?(n[0]=ce(n[0]),r[t](...n)):o}function Dn(e,t,n=[]){Kt(),Jo();const r=ce(e)[t].apply(e,n);return Qo(),Gt(),r}const uc=Ko("__proto__,__v_isRef,__isVue"),sl=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(Ut));function fc(e){Ut(e)||(e=String(e));const t=ce(this);return Ue(t,"has",e),t.hasOwnProperty(e)}class il{constructor(t=!1,n=!1){this._isReadonly=t,this._isShallow=n}get(t,n,r){const o=this._isReadonly,s=this._isShallow;if(n==="__v_isReactive")return!o;if(n==="__v_isReadonly")return o;if(n==="__v_isShallow")return s;if(n==="__v_raw")return r===(o?s?Pc:ul:s?cl:al).get(t)||Object.getPrototypeOf(t)===Object.getPrototypeOf(r)?t:void 0;const i=te(t);if(!o){let a;if(i&&(a=ac[n]))return a;if(n==="hasOwnProperty")return fc}const l=Reflect.get(t,n,Oe(t)?t:r);return(Ut(n)?sl.has(n):uc(n))||(o||Ue(t,"get",n),s)?l:Oe(l)?i&&Yo(n)?l:l.value:Ee(l)?o?Xr(l):lr(l):l}}class ll extends il{constructor(t=!1){super(!1,t)}set(t,n,r,o){let s=t[n];if(!this._isShallow){const a=un(s);if(!lt(r)&&!un(r)&&(s=ce(s),r=ce(r)),!te(t)&&Oe(s)&&!Oe(r))return a?!1:(s.value=r,!0)}const i=te(t)&&Yo(n)?Number(n)e,Qr=e=>Reflect.getPrototypeOf(e);function gr(e,t,n=!1,r=!1){e=e.__v_raw;const o=ce(e),s=ce(t);n||(jt(t,s)&&Ue(o,"get",t),Ue(o,"get",s));const{has:i}=Qr(o),l=r?Zo:n?rs:je;if(i.call(o,t))return l(e.get(t));if(i.call(o,s))return l(e.get(s));e!==o&&e.get(t)}function vr(e,t=!1){const n=this.__v_raw,r=ce(n),o=ce(e);return t||(jt(e,o)&&Ue(r,"has",e),Ue(r,"has",o)),e===o?n.has(e):n.has(e)||n.has(o)}function _r(e,t=!1){return e=e.__v_raw,!t&&Ue(ce(e),"iterate",rn),Reflect.get(e,"size",e)}function Os(e,t=!1){!t&&!lt(e)&&!un(e)&&(e=ce(e));const n=ce(this);return Qr(n).has.call(n,e)||(n.add(e),Tt(n,"add",e,e)),this}function Rs(e,t,n=!1){!n&&!lt(t)&&!un(t)&&(t=ce(t));const r=ce(this),{has:o,get:s}=Qr(r);let i=o.call(r,e);i||(e=ce(e),i=o.call(r,e));const l=s.call(r,e);return r.set(e,t),i?jt(t,l)&&Tt(r,"set",e,t):Tt(r,"add",e,t),this}function Is(e){const t=ce(this),{has:n,get:r}=Qr(t);let o=n.call(t,e);o||(e=ce(e),o=n.call(t,e)),r&&r.call(t,e);const s=t.delete(e);return o&&Tt(t,"delete",e,void 0),s}function Ds(){const e=ce(this),t=e.size!==0,n=e.clear();return t&&Tt(e,"clear",void 0,void 0),n}function br(e,t){return function(r,o){const s=this,i=s.__v_raw,l=ce(i),a=t?Zo:e?rs:je;return!e&&Ue(l,"iterate",rn),i.forEach((f,u)=>r.call(o,a(f),a(u),s))}}function yr(e,t,n){return function(...r){const o=this.__v_raw,s=ce(o),i=yn(s),l=e==="entries"||e===Symbol.iterator&&i,a=e==="keys"&&i,f=o[e](...r),u=n?Zo:t?rs:je;return!t&&Ue(s,"iterate",a?Ao:rn),{next(){const{value:c,done:p}=f.next();return p?{value:c,done:p}:{value:l?[u(c[0]),u(c[1])]:u(c),done:p}},[Symbol.iterator](){return this}}}}function It(e){return function(...t){return e==="delete"?!1:e==="clear"?void 0:this}}function gc(){const e={get(s){return gr(this,s)},get size(){return _r(this)},has:vr,add:Os,set:Rs,delete:Is,clear:Ds,forEach:br(!1,!1)},t={get(s){return gr(this,s,!1,!0)},get size(){return _r(this)},has:vr,add(s){return Os.call(this,s,!0)},set(s,i){return Rs.call(this,s,i,!0)},delete:Is,clear:Ds,forEach:br(!1,!0)},n={get(s){return gr(this,s,!0)},get size(){return _r(this,!0)},has(s){return vr.call(this,s,!0)},add:It("add"),set:It("set"),delete:It("delete"),clear:It("clear"),forEach:br(!0,!1)},r={get(s){return gr(this,s,!0,!0)},get size(){return _r(this,!0)},has(s){return vr.call(this,s,!0)},add:It("add"),set:It("set"),delete:It("delete"),clear:It("clear"),forEach:br(!0,!0)};return["keys","values","entries",Symbol.iterator].forEach(s=>{e[s]=yr(s,!1,!1),n[s]=yr(s,!0,!1),t[s]=yr(s,!1,!0),r[s]=yr(s,!0,!0)}),[e,n,t,r]}const[vc,_c,bc,yc]=gc();function es(e,t){const n=t?e?yc:bc:e?_c:vc;return(r,o,s)=>o==="__v_isReactive"?!e:o==="__v_isReadonly"?e:o==="__v_raw"?r:Reflect.get(ue(n,o)&&o in r?n:r,o,s)}const Ec={get:es(!1,!1)},wc={get:es(!1,!0)},Sc={get:es(!0,!1)};const al=new WeakMap,cl=new WeakMap,ul=new WeakMap,Pc=new WeakMap;function xc(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function Lc(e){return e.__v_skip||!Object.isExtensible(e)?0:xc(Ka(e))}function lr(e){return un(e)?e:ts(e,!1,pc,Ec,al)}function fl(e){return ts(e,!1,mc,wc,cl)}function Xr(e){return ts(e,!0,hc,Sc,ul)}function ts(e,t,n,r,o){if(!Ee(e)||e.__v_raw&&!(t&&e.__v_isReactive))return e;const s=o.get(e);if(s)return s;const i=Lc(e);if(i===0)return e;const l=new Proxy(e,i===2?r:n);return o.set(e,l),l}function on(e){return un(e)?on(e.__v_raw):!!(e&&e.__v_isReactive)}function un(e){return!!(e&&e.__v_isReadonly)}function lt(e){return!!(e&&e.__v_isShallow)}function ns(e){return e?!!e.__v_raw:!1}function ce(e){const t=e&&e.__v_raw;return t?ce(t):e}function Cc(e){return!ue(e,"__v_skip")&&Object.isExtensible(e)&&Wi(e,"__v_skip",!0),e}const je=e=>Ee(e)?lr(e):e,rs=e=>Ee(e)?Xr(e):e;function Oe(e){return e?e.__v_isRef===!0:!1}function ge(e){return dl(e,!1)}function fn(e){return dl(e,!0)}function dl(e,t){return Oe(e)?e:new Tc(e,t)}class Tc{constructor(t,n){this.dep=new Yr,this.__v_isRef=!0,this.__v_isShallow=!1,this._rawValue=n?t:ce(t),this._value=n?t:je(t),this.__v_isShallow=n}get value(){return this.dep.track(),this._value}set value(t){const n=this._rawValue,r=this.__v_isShallow||lt(t)||un(t);t=r?t:ce(t),jt(t,n)&&(this._rawValue=t,this._value=r?t:je(t),this.dep.trigger())}}function sn(e){return Oe(e)?e.value:e}const kc={get:(e,t,n)=>t==="__v_raw"?e:sn(Reflect.get(e,t,n)),set:(e,t,n,r)=>{const o=e[t];return Oe(o)&&!Oe(n)?(o.value=n,!0):Reflect.set(e,t,n,r)}};function pl(e){return on(e)?e:new Proxy(e,kc)}class Ac{constructor(t){this.__v_isRef=!0,this._value=void 0;const n=this.dep=new Yr,{get:r,set:o}=t(n.track.bind(n),n.trigger.bind(n));this._get=r,this._set=o}get value(){return this._value=this._get()}set value(t){this._set(t)}}function Oc(e){return new Ac(e)}function hl(e){const t=te(e)?new Array(e.length):{};for(const n in e)t[n]=ml(e,n);return t}class Rc{constructor(t,n,r){this._object=t,this._key=n,this._defaultValue=r,this.__v_isRef=!0,this._value=void 0}get value(){const t=this._object[this._key];return this._value=t===void 0?this._defaultValue:t}set value(t){this._object[this._key]=t}get dep(){return lc(ce(this._object),this._key)}}class Ic{constructor(t){this._getter=t,this.__v_isRef=!0,this.__v_isReadonly=!0,this._value=void 0}get value(){return this._value=this._getter()}}function Dc(e,t,n){return Oe(e)?e:oe(e)?new Ic(e):Ee(e)&&arguments.length>1?ml(e,t,n):ge(e)}function ml(e,t,n){const r=e[t];return Oe(r)?r:new Rc(e,t,n)}class Mc{constructor(t,n,r){this.fn=t,this.setter=n,this._value=void 0,this.dep=new Yr(this),this.__v_isRef=!0,this.deps=void 0,this.depsTail=void 0,this.flags=16,this.globalVersion=Kn-1,this.effect=this,this.__v_isReadonly=!n,this.isSSR=r}notify(){if(this.flags|=16,!(this.flags&8)&&ve!==this)return Zi(this),!0}get value(){const t=this.dep.track();return nl(this),t&&(t.version=this.dep.version),this._value}set value(t){this.setter&&this.setter(t)}}function Vc(e,t,n=!1){let r,o;return oe(e)?r=e:(r=e.get,o=e.set),new Mc(r,o,n)}const Er={},Mr=new WeakMap;let en;function Hc(e,t=!1,n=en){if(n){let r=Mr.get(n);r||Mr.set(n,r=[]),r.push(e)}}function $c(e,t,n=_e){const{immediate:r,deep:o,once:s,scheduler:i,augmentJob:l,call:a}=n,f=b=>o?b:lt(b)||o===!1||o===0?Ct(b,1):Ct(b);let u,c,p,m,v=!1,y=!1;if(Oe(e)?(c=()=>e.value,v=lt(e)):on(e)?(c=()=>f(e),v=!0):te(e)?(y=!0,v=e.some(b=>on(b)||lt(b)),c=()=>e.map(b=>{if(Oe(b))return b.value;if(on(b))return f(b);if(oe(b))return a?a(b,2):b()})):oe(e)?t?c=a?()=>a(e,2):e:c=()=>{if(p){Kt();try{p()}finally{Gt()}}const b=en;en=u;try{return a?a(e,3,[m]):e(m)}finally{en=b}}:c=vt,t&&o){const b=c,V=o===!0?1/0:o;c=()=>Ct(b(),V)}const C=Ji(),T=()=>{u.stop(),C&&qo(C.effects,u)};if(s&&t){const b=t;t=(...V)=>{b(...V),T()}}let S=y?new Array(e.length).fill(Er):Er;const g=b=>{if(!(!(u.flags&1)||!u.dirty&&!b))if(t){const V=u.run();if(o||v||(y?V.some((q,D)=>jt(q,S[D])):jt(V,S))){p&&p();const q=en;en=u;try{const D=[V,S===Er?void 0:y&&S[0]===Er?[]:S,m];a?a(t,3,D):t(...D),S=V}finally{en=q}}}else u.run()};return l&&l(g),u=new Qi(c),u.scheduler=i?()=>i(g,!1):g,m=b=>Hc(b,!1,u),p=u.onStop=()=>{const b=Mr.get(u);if(b){if(a)a(b,4);else for(const V of b)V();Mr.delete(u)}},t?r?g(!0):S=u.run():i?i(g.bind(null,!0),!0):u.run(),T.pause=u.pause.bind(u),T.resume=u.resume.bind(u),T.stop=T,T}function Ct(e,t=1/0,n){if(t<=0||!Ee(e)||e.__v_skip||(n=n||new Set,n.has(e)))return e;if(n.add(e),t--,Oe(e))Ct(e.value,t,n);else if(te(e))for(let r=0;r{Ct(r,t,n)});else if(Ui(e)){for(const r in e)Ct(e[r],t,n);for(const r of Object.getOwnPropertySymbols(e))Object.prototype.propertyIsEnumerable.call(e,r)&&Ct(e[r],t,n)}return e}/** +* @vue/runtime-core v3.5.8 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/function ar(e,t,n,r){try{return r?e(...r):e()}catch(o){cr(o,t,n)}}function ft(e,t,n,r){if(oe(e)){const o=ar(e,t,n,r);return o&&Fi(o)&&o.catch(s=>{cr(s,t,n)}),o}if(te(e)){const o=[];for(let s=0;s>>1,o=qe[r],s=Jn(o);s=Jn(n)?qe.push(e):qe.splice(jc(t),0,e),e.flags|=1,vl()}}function vl(){!Yn&&!Oo&&(Oo=!0,os=gl.then(_l))}function Bc(e){te(e)?wn.push(...e):Vt&&e.id===-1?Vt.splice(gn+1,0,e):e.flags&1||(wn.push(e),e.flags|=1),vl()}function Ms(e,t,n=Yn?mt+1:0){for(;nJn(n)-Jn(r));if(wn.length=0,Vt){Vt.push(...t);return}for(Vt=t,gn=0;gne.id==null?e.flags&2?-1:1/0:e.id;function _l(e){Oo=!1,Yn=!0;try{for(mt=0;mt{r._d&&Gs(-1);const s=Hr(t);let i;try{i=e(...o)}finally{Hr(s),r._d&&Gs(1)}return i};return r._n=!0,r._c=!0,r._d=!0,r}function $r(e,t){if(Me===null)return e;const n=no(Me),r=e.dirs||(e.dirs=[]);for(let o=0;oe.__isTeleport,Ht=Symbol("_leaveCb"),wr=Symbol("_enterCb");function zc(){const e={isMounted:!1,isLeaving:!1,isUnmounting:!1,leavingVNodes:new Map};return We(()=>{e.isMounted=!0}),ls(()=>{e.isUnmounting=!0}),e}const ot=[Function,Array],El={mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:ot,onEnter:ot,onAfterEnter:ot,onEnterCancelled:ot,onBeforeLeave:ot,onLeave:ot,onAfterLeave:ot,onLeaveCancelled:ot,onBeforeAppear:ot,onAppear:ot,onAfterAppear:ot,onAppearCancelled:ot},wl=e=>{const t=e.subTree;return t.component?wl(t.component):t},Uc={name:"BaseTransition",props:El,setup(e,{slots:t}){const n=dr(),r=zc();return()=>{const o=t.default&&xl(t.default(),!0);if(!o||!o.length)return;const s=Sl(o),i=ce(e),{mode:l}=i;if(r.isLeaving)return mo(s);const a=Vs(s);if(!a)return mo(s);let f=Ro(a,i,r,n,p=>f=p);a.type!==Be&&Qn(a,f);const u=n.subTree,c=u&&Vs(u);if(c&&c.type!==Be&&!nn(a,c)&&wl(n).type!==Be){const p=Ro(c,i,r,n);if(Qn(c,p),l==="out-in"&&a.type!==Be)return r.isLeaving=!0,p.afterLeave=()=>{r.isLeaving=!1,n.job.flags&8||n.update(),delete p.afterLeave},mo(s);l==="in-out"&&a.type!==Be&&(p.delayLeave=(m,v,y)=>{const C=Pl(r,c);C[String(c.key)]=c,m[Ht]=()=>{v(),m[Ht]=void 0,delete f.delayedLeave},f.delayedLeave=y})}return s}}};function Sl(e){let t=e[0];if(e.length>1){for(const n of e)if(n.type!==Be){t=n;break}}return t}const Wc=Uc;function Pl(e,t){const{leavingVNodes:n}=e;let r=n.get(t.type);return r||(r=Object.create(null),n.set(t.type,r)),r}function Ro(e,t,n,r,o){const{appear:s,mode:i,persisted:l=!1,onBeforeEnter:a,onEnter:f,onAfterEnter:u,onEnterCancelled:c,onBeforeLeave:p,onLeave:m,onAfterLeave:v,onLeaveCancelled:y,onBeforeAppear:C,onAppear:T,onAfterAppear:S,onAppearCancelled:g}=t,b=String(e.key),V=Pl(n,e),q=(z,x)=>{z&&ft(z,r,9,x)},D=(z,x)=>{const j=x[1];q(z,x),te(z)?z.every(E=>E.length<=1)&&j():z.length<=1&&j()},w={mode:i,persisted:l,beforeEnter(z){let x=a;if(!n.isMounted)if(s)x=C||a;else return;z[Ht]&&z[Ht](!0);const j=V[b];j&&nn(e,j)&&j.el[Ht]&&j.el[Ht](),q(x,[z])},enter(z){let x=f,j=u,E=c;if(!n.isMounted)if(s)x=T||f,j=S||u,E=g||c;else return;let M=!1;const X=z[wr]=ie=>{M||(M=!0,ie?q(E,[z]):q(j,[z]),w.delayedLeave&&w.delayedLeave(),z[wr]=void 0)};x?D(x,[z,X]):X()},leave(z,x){const j=String(e.key);if(z[wr]&&z[wr](!0),n.isUnmounting)return x();q(p,[z]);let E=!1;const M=z[Ht]=X=>{E||(E=!0,x(),X?q(y,[z]):q(v,[z]),z[Ht]=void 0,V[j]===e&&delete V[j])};V[j]=e,m?D(m,[z,M]):M()},clone(z){const x=Ro(z,t,n,r,o);return o&&o(x),x}};return w}function mo(e){if(ur(e))return e=Ft(e),e.children=null,e}function Vs(e){if(!ur(e))return yl(e.type)&&e.children?Sl(e.children):e;const{shapeFlag:t,children:n}=e;if(n){if(t&16)return n[0];if(t&32&&oe(n.default))return n.default()}}function Qn(e,t){e.shapeFlag&6&&e.component?(e.transition=t,Qn(e.component.subTree,t)):e.shapeFlag&128?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function xl(e,t=!1,n){let r=[],o=0;for(let s=0;s1)for(let s=0;sNr(v,t&&(te(t)?t[y]:t),n,r,o));return}if(ln(r)&&!o)return;const s=r.shapeFlag&4?no(r.component):r.el,i=o?null:s,{i:l,r:a}=e,f=t&&t.r,u=l.refs===_e?l.refs={}:l.refs,c=l.setupState,p=ce(c),m=c===_e?()=>!1:v=>ue(p,v);if(f!=null&&f!==a&&(Te(f)?(u[f]=null,m(f)&&(c[f]=null)):Oe(f)&&(f.value=null)),oe(a))ar(a,l,12,[i,u]);else{const v=Te(a),y=Oe(a);if(v||y){const C=()=>{if(e.f){const T=v?m(a)?c[a]:u[a]:a.value;o?te(T)&&qo(T,s):te(T)?T.includes(s)||T.push(s):v?(u[a]=[s],m(a)&&(c[a]=u[a])):(a.value=[s],e.k&&(u[e.k]=a.value))}else v?(u[a]=i,m(a)&&(c[a]=i)):y&&(a.value=i,e.k&&(u[e.k]=i))};i?(C.id=-1,tt(C,n)):C()}}}let Hs=!1;const hn=()=>{Hs||(console.error("Hydration completed but contains mismatches."),Hs=!0)},Kc=e=>e.namespaceURI.includes("svg")&&e.tagName!=="foreignObject",Gc=e=>e.namespaceURI.includes("MathML"),Sr=e=>{if(e.nodeType===1){if(Kc(e))return"svg";if(Gc(e))return"mathml"}},_n=e=>e.nodeType===8;function qc(e){const{mt:t,p:n,o:{patchProp:r,createText:o,nextSibling:s,parentNode:i,remove:l,insert:a,createComment:f}}=e,u=(g,b)=>{if(!b.hasChildNodes()){n(null,g,b),Vr(),b._vnode=g;return}c(b.firstChild,g,null,null,null),Vr(),b._vnode=g},c=(g,b,V,q,D,w=!1)=>{w=w||!!b.dynamicChildren;const z=_n(g)&&g.data==="[",x=()=>y(g,b,V,q,D,z),{type:j,ref:E,shapeFlag:M,patchFlag:X}=b;let ie=g.nodeType;b.el=g,X===-2&&(w=!1,b.dynamicChildren=null);let I=null;switch(j){case cn:ie!==3?b.children===""?(a(b.el=o(""),i(g),g),I=g):I=x():(g.data!==b.children&&(hn(),g.data=b.children),I=s(g));break;case Be:S(g)?(I=s(g),T(b.el=g.content.firstChild,g,V)):ie!==8||z?I=x():I=s(g);break;case Pn:if(z&&(g=s(g),ie=g.nodeType),ie===1||ie===3){I=g;const J=!b.children.length;for(let W=0;W{w=w||!!b.dynamicChildren;const{type:z,props:x,patchFlag:j,shapeFlag:E,dirs:M,transition:X}=b,ie=z==="input"||z==="option";if(ie||j!==-1){M&>(b,null,V,"created");let I=!1;if(S(g)){I=Bl(q,X)&&V&&V.vnode.props&&V.vnode.props.appear;const W=g.content.firstChild;I&&X.beforeEnter(W),T(W,g,V),b.el=g=W}if(E&16&&!(x&&(x.innerHTML||x.textContent))){let W=m(g.firstChild,b,g,V,q,D,w);for(;W;){Pr(g,1)||hn();const be=W;W=W.nextSibling,l(be)}}else if(E&8){let W=b.children;W[0]===` +`&&(g.tagName==="PRE"||g.tagName==="TEXTAREA")&&(W=W.slice(1)),g.textContent!==W&&(Pr(g,0)||hn(),g.textContent=b.children)}if(x){if(ie||!w||j&48){const W=g.tagName.includes("-");for(const be in x)(ie&&(be.endsWith("value")||be==="indeterminate")||or(be)&&!En(be)||be[0]==="."||W)&&r(g,be,null,x[be],void 0,V)}else if(x.onClick)r(g,"onClick",null,x.onClick,void 0,V);else if(j&4&&on(x.style))for(const W in x.style)x.style[W]}let J;(J=x&&x.onVnodeBeforeMount)&&st(J,V,b),M&>(b,null,V,"beforeMount"),((J=x&&x.onVnodeMounted)||M||I)&&Gl(()=>{J&&st(J,V,b),I&&X.enter(g),M&>(b,null,V,"mounted")},q)}return g.nextSibling},m=(g,b,V,q,D,w,z)=>{z=z||!!b.dynamicChildren;const x=b.children,j=x.length;for(let E=0;E{const{slotScopeIds:z}=b;z&&(D=D?D.concat(z):z);const x=i(g),j=m(s(g),b,x,V,q,D,w);return j&&_n(j)&&j.data==="]"?s(b.anchor=j):(hn(),a(b.anchor=f("]"),x,j),j)},y=(g,b,V,q,D,w)=>{if(Pr(g.parentElement,1)||hn(),b.el=null,w){const j=C(g);for(;;){const E=s(g);if(E&&E!==j)l(E);else break}}const z=s(g),x=i(g);return l(g),n(null,b,x,z,V,q,Sr(x),D),z},C=(g,b="[",V="]")=>{let q=0;for(;g;)if(g=s(g),g&&_n(g)&&(g.data===b&&q++,g.data===V)){if(q===0)return s(g);q--}return g},T=(g,b,V)=>{const q=b.parentNode;q&&q.replaceChild(g,b);let D=V;for(;D;)D.vnode.el===b&&(D.vnode.el=D.subTree.el=g),D=D.parent},S=g=>g.nodeType===1&&g.tagName==="TEMPLATE";return[u,c]}const $s="data-allow-mismatch",Yc={0:"text",1:"children",2:"class",3:"style",4:"attribute"};function Pr(e,t){if(t===0||t===1)for(;e&&!e.hasAttribute($s);)e=e.parentElement;const n=e&&e.getAttribute($s);if(n==null)return!1;if(n==="")return!0;{const r=n.split(",");return t===0&&r.includes("children")?!0:n.split(",").includes(Yc[t])}}function Jc(e,t){if(_n(e)&&e.data==="["){let n=1,r=e.nextSibling;for(;r;){if(r.nodeType===1){if(t(r)===!1)break}else if(_n(r))if(r.data==="]"){if(--n===0)break}else r.data==="["&&n++;r=r.nextSibling}}else t(e)}const ln=e=>!!e.type.__asyncLoader;/*! #__NO_SIDE_EFFECTS__ */function Se(e){oe(e)&&(e={loader:e});const{loader:t,loadingComponent:n,errorComponent:r,delay:o=200,hydrate:s,timeout:i,suspensible:l=!0,onError:a}=e;let f=null,u,c=0;const p=()=>(c++,f=null,m()),m=()=>{let v;return f||(v=f=t().catch(y=>{if(y=y instanceof Error?y:new Error(String(y)),a)return new Promise((C,T)=>{a(y,()=>C(p()),()=>T(y),c+1)});throw y}).then(y=>v!==f&&f?f:(y&&(y.__esModule||y[Symbol.toStringTag]==="Module")&&(y=y.default),u=y,y)))};return fe({name:"AsyncComponentWrapper",__asyncLoader:m,__asyncHydrate(v,y,C){const T=s?()=>{const S=s(C,g=>Jc(v,g));S&&(y.bum||(y.bum=[])).push(S)}:C;u?T():m().then(()=>!y.isUnmounted&&T())},get __asyncResolved(){return u},setup(){const v=De;if(is(v),u)return()=>go(u,v);const y=g=>{f=null,cr(g,v,13,!r)};if(l&&v.suspense||hr)return m().then(g=>()=>go(g,v)).catch(g=>(y(g),()=>r?se(r,{error:g}):null));const C=ge(!1),T=ge(),S=ge(!!o);return o&&setTimeout(()=>{S.value=!1},o),i!=null&&setTimeout(()=>{if(!C.value&&!T.value){const g=new Error(`Async component timed out after ${i}ms.`);y(g),T.value=g}},i),m().then(()=>{C.value=!0,v.parent&&ur(v.parent.vnode)&&v.parent.update()}).catch(g=>{y(g),T.value=g}),()=>{if(C.value&&u)return go(u,v);if(T.value&&r)return se(r,{error:T.value});if(n&&!S.value)return se(n)}}})}function go(e,t){const{ref:n,props:r,children:o,ce:s}=t.vnode,i=se(e,r,o);return i.ref=n,i.ce=s,delete t.vnode.ce,i}const ur=e=>e.type.__isKeepAlive;function Qc(e,t){Ll(e,"a",t)}function Xc(e,t){Ll(e,"da",t)}function Ll(e,t,n=De){const r=e.__wdc||(e.__wdc=()=>{let o=n;for(;o;){if(o.isDeactivated)return;o=o.parent}return e()});if(Zr(t,r,n),n){let o=n.parent;for(;o&&o.parent;)ur(o.parent.vnode)&&Zc(r,t,n,o),o=o.parent}}function Zc(e,t,n,r){const o=Zr(t,e,r,!0);fr(()=>{qo(r[t],o)},n)}function Zr(e,t,n=De,r=!1){if(n){const o=n[e]||(n[e]=[]),s=t.__weh||(t.__weh=(...i)=>{Kt();const l=pr(n),a=ft(t,n,e,i);return l(),Gt(),a});return r?o.unshift(s):o.push(s),s}}const kt=e=>(t,n=De)=>{(!hr||e==="sp")&&Zr(e,(...r)=>t(...r),n)},Cl=kt("bm"),We=kt("m"),eu=kt("bu"),tu=kt("u"),ls=kt("bum"),fr=kt("um"),nu=kt("sp"),ru=kt("rtg"),ou=kt("rtc");function su(e,t=De){Zr("ec",e,t)}const Tl="components";function as(e,t){return lu(Tl,e,!0,t)||e}const iu=Symbol.for("v-ndc");function lu(e,t,n=!0,r=!1){const o=Me||De;if(o){const s=o.type;if(e===Tl){const l=qu(s,!1);if(l&&(l===t||l===rt(t)||l===sr(rt(t))))return s}const i=Ns(o[e]||s[e],t)||Ns(o.appContext[e],t);return!i&&r?s:i}}function Ns(e,t){return e&&(e[t]||e[rt(t)]||e[sr(rt(t))])}function Bt(e,t,n,r){let o;const s=n,i=te(e);if(i||Te(e)){const l=i&&on(e);let a=!1;l&&(a=!lt(e),e=Jr(e)),o=new Array(e.length);for(let f=0,u=e.length;ft(l,a,void 0,s));else{const l=Object.keys(e);o=new Array(l.length);for(let a=0,f=l.length;aBr(t)?!(t.type===Be||t.type===me&&!kl(t.children)):!0)?e:null}const Io=e=>e?Jl(e)?no(e):Io(e.parent):null,Fn=Re(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>Io(e.parent),$root:e=>Io(e.root),$host:e=>e.ce,$emit:e=>e.emit,$options:e=>cs(e),$forceUpdate:e=>e.f||(e.f=()=>{ss(e.update)}),$nextTick:e=>e.n||(e.n=An.bind(e.proxy)),$watch:e=>ku.bind(e)}),vo=(e,t)=>e!==_e&&!e.__isScriptSetup&&ue(e,t),au={get({_:e},t){if(t==="__v_skip")return!0;const{ctx:n,setupState:r,data:o,props:s,accessCache:i,type:l,appContext:a}=e;let f;if(t[0]!=="$"){const m=i[t];if(m!==void 0)switch(m){case 1:return r[t];case 2:return o[t];case 4:return n[t];case 3:return s[t]}else{if(vo(r,t))return i[t]=1,r[t];if(o!==_e&&ue(o,t))return i[t]=2,o[t];if((f=e.propsOptions[0])&&ue(f,t))return i[t]=3,s[t];if(n!==_e&&ue(n,t))return i[t]=4,n[t];Do&&(i[t]=0)}}const u=Fn[t];let c,p;if(u)return t==="$attrs"&&Ue(e.attrs,"get",""),u(e);if((c=l.__cssModules)&&(c=c[t]))return c;if(n!==_e&&ue(n,t))return i[t]=4,n[t];if(p=a.config.globalProperties,ue(p,t))return p[t]},set({_:e},t,n){const{data:r,setupState:o,ctx:s}=e;return vo(o,t)?(o[t]=n,!0):r!==_e&&ue(r,t)?(r[t]=n,!0):ue(e.props,t)||t[0]==="$"&&t.slice(1)in e?!1:(s[t]=n,!0)},has({_:{data:e,setupState:t,accessCache:n,ctx:r,appContext:o,propsOptions:s}},i){let l;return!!n[i]||e!==_e&&ue(e,i)||vo(t,i)||(l=s[0])&&ue(l,i)||ue(r,i)||ue(Fn,i)||ue(o.config.globalProperties,i)},defineProperty(e,t,n){return n.get!=null?e._.accessCache[t]=0:ue(n,"value")&&this.set(e,t,n.value,null),Reflect.defineProperty(e,t,n)}};function js(e){return te(e)?e.reduce((t,n)=>(t[n]=null,t),{}):e}let Do=!0;function cu(e){const t=cs(e),n=e.proxy,r=e.ctx;Do=!1,t.beforeCreate&&Bs(t.beforeCreate,e,"bc");const{data:o,computed:s,methods:i,watch:l,provide:a,inject:f,created:u,beforeMount:c,mounted:p,beforeUpdate:m,updated:v,activated:y,deactivated:C,beforeDestroy:T,beforeUnmount:S,destroyed:g,unmounted:b,render:V,renderTracked:q,renderTriggered:D,errorCaptured:w,serverPrefetch:z,expose:x,inheritAttrs:j,components:E,directives:M,filters:X}=t;if(f&&uu(f,r,null),i)for(const J in i){const W=i[J];oe(W)&&(r[J]=W.bind(n))}if(o){const J=o.call(n,n);Ee(J)&&(e.data=lr(J))}if(Do=!0,s)for(const J in s){const W=s[J],be=oe(W)?W.bind(n,n):oe(W.get)?W.get.bind(n,n):vt,He=!oe(W)&&oe(W.set)?W.set.bind(n):vt,Ye=H({get:be,set:He});Object.defineProperty(r,J,{enumerable:!0,configurable:!0,get:()=>Ye.value,set:$e=>Ye.value=$e})}if(l)for(const J in l)Al(l[J],r,n,J);if(a){const J=oe(a)?a.call(n):a;Reflect.ownKeys(J).forEach(W=>{an(W,J[W])})}u&&Bs(u,e,"c");function I(J,W){te(W)?W.forEach(be=>J(be.bind(n))):W&&J(W.bind(n))}if(I(Cl,c),I(We,p),I(eu,m),I(tu,v),I(Qc,y),I(Xc,C),I(su,w),I(ou,q),I(ru,D),I(ls,S),I(fr,b),I(nu,z),te(x))if(x.length){const J=e.exposed||(e.exposed={});x.forEach(W=>{Object.defineProperty(J,W,{get:()=>n[W],set:be=>n[W]=be})})}else e.exposed||(e.exposed={});V&&e.render===vt&&(e.render=V),j!=null&&(e.inheritAttrs=j),E&&(e.components=E),M&&(e.directives=M),z&&is(e)}function uu(e,t,n=vt){te(e)&&(e=Mo(e));for(const r in e){const o=e[r];let s;Ee(o)?"default"in o?s=Fe(o.from||r,o.default,!0):s=Fe(o.from||r):s=Fe(o),Oe(s)?Object.defineProperty(t,r,{enumerable:!0,configurable:!0,get:()=>s.value,set:i=>s.value=i}):t[r]=s}}function Bs(e,t,n){ft(te(e)?e.map(r=>r.bind(t.proxy)):e.bind(t.proxy),t,n)}function Al(e,t,n,r){let o=r.includes(".")?Ul(n,r):()=>n[r];if(Te(e)){const s=t[e];oe(s)&&ze(o,s)}else if(oe(e))ze(o,e.bind(n));else if(Ee(e))if(te(e))e.forEach(s=>Al(s,t,n,r));else{const s=oe(e.handler)?e.handler.bind(n):t[e.handler];oe(s)&&ze(o,s,e)}}function cs(e){const t=e.type,{mixins:n,extends:r}=t,{mixins:o,optionsCache:s,config:{optionMergeStrategies:i}}=e.appContext,l=s.get(t);let a;return l?a=l:!o.length&&!n&&!r?a=t:(a={},o.length&&o.forEach(f=>jr(a,f,i,!0)),jr(a,t,i)),Ee(t)&&s.set(t,a),a}function jr(e,t,n,r=!1){const{mixins:o,extends:s}=t;s&&jr(e,s,n,!0),o&&o.forEach(i=>jr(e,i,n,!0));for(const i in t)if(!(r&&i==="expose")){const l=fu[i]||n&&n[i];e[i]=l?l(e[i],t[i]):t[i]}return e}const fu={data:Fs,props:zs,emits:zs,methods:Nn,computed:Nn,beforeCreate:Ke,created:Ke,beforeMount:Ke,mounted:Ke,beforeUpdate:Ke,updated:Ke,beforeDestroy:Ke,beforeUnmount:Ke,destroyed:Ke,unmounted:Ke,activated:Ke,deactivated:Ke,errorCaptured:Ke,serverPrefetch:Ke,components:Nn,directives:Nn,watch:pu,provide:Fs,inject:du};function Fs(e,t){return t?e?function(){return Re(oe(e)?e.call(this,this):e,oe(t)?t.call(this,this):t)}:t:e}function du(e,t){return Nn(Mo(e),Mo(t))}function Mo(e){if(te(e)){const t={};for(let n=0;n1)return n&&oe(t)?t.call(r&&r.proxy):t}}const Rl={},Il=()=>Object.create(Rl),Dl=e=>Object.getPrototypeOf(e)===Rl;function gu(e,t,n,r=!1){const o={},s=Il();e.propsDefaults=Object.create(null),Ml(e,t,o,s);for(const i in e.propsOptions[0])i in o||(o[i]=void 0);n?e.props=r?o:fl(o):e.type.props?e.props=o:e.props=s,e.attrs=s}function vu(e,t,n,r){const{props:o,attrs:s,vnode:{patchFlag:i}}=e,l=ce(o),[a]=e.propsOptions;let f=!1;if((r||i>0)&&!(i&16)){if(i&8){const u=e.vnode.dynamicProps;for(let c=0;c{a=!0;const[p,m]=Vl(c,t,!0);Re(i,p),m&&l.push(...m)};!n&&t.mixins.length&&t.mixins.forEach(u),e.extends&&u(e.extends),e.mixins&&e.mixins.forEach(u)}if(!s&&!a)return Ee(e)&&r.set(e,bn),bn;if(te(s))for(let u=0;ue[0]==="_"||e==="$stable",us=e=>te(e)?e.map(it):[it(e)],bu=(e,t,n)=>{if(t._n)return t;const r=ke((...o)=>us(t(...o)),n);return r._c=!1,r},$l=(e,t,n)=>{const r=e._ctx;for(const o in e){if(Hl(o))continue;const s=e[o];if(oe(s))t[o]=bu(o,s,r);else if(s!=null){const i=us(s);t[o]=()=>i}}},Nl=(e,t)=>{const n=us(t);e.slots.default=()=>n},jl=(e,t,n)=>{for(const r in t)(n||r!=="_")&&(e[r]=t[r])},yu=(e,t,n)=>{const r=e.slots=Il();if(e.vnode.shapeFlag&32){const o=t._;o?(jl(r,t,n),n&&Wi(r,"_",o,!0)):$l(t,r)}else t&&Nl(e,t)},Eu=(e,t,n)=>{const{vnode:r,slots:o}=e;let s=!0,i=_e;if(r.shapeFlag&32){const l=t._;l?n&&l===1?s=!1:jl(o,t,n):(s=!t.$stable,$l(t,o)),i=t}else t&&(Nl(e,t),i={default:1});if(s)for(const l in o)!Hl(l)&&i[l]==null&&delete o[l]},tt=Gl;function wu(e){return Su(e,qc)}function Su(e,t){const n=Ki();n.__VUE__=!0;const{insert:r,remove:o,patchProp:s,createElement:i,createText:l,createComment:a,setText:f,setElementText:u,parentNode:c,nextSibling:p,setScopeId:m=vt,insertStaticContent:v}=e,y=(d,h,_,k=null,P=null,A=null,F=void 0,N=null,$=!!h.dynamicChildren)=>{if(d===h)return;d&&!nn(d,h)&&(k=L(d),$e(d,P,A,!0),d=null),h.patchFlag===-2&&($=!1,h.dynamicChildren=null);const{type:R,ref:Z,shapeFlag:G}=h;switch(R){case cn:C(d,h,_,k);break;case Be:T(d,h,_,k);break;case Pn:d==null&&S(h,_,k,F);break;case me:E(d,h,_,k,P,A,F,N,$);break;default:G&1?V(d,h,_,k,P,A,F,N,$):G&6?M(d,h,_,k,P,A,F,N,$):(G&64||G&128)&&R.process(d,h,_,k,P,A,F,N,$,Y)}Z!=null&&P&&Nr(Z,d&&d.ref,A,h||d,!h)},C=(d,h,_,k)=>{if(d==null)r(h.el=l(h.children),_,k);else{const P=h.el=d.el;h.children!==d.children&&f(P,h.children)}},T=(d,h,_,k)=>{d==null?r(h.el=a(h.children||""),_,k):h.el=d.el},S=(d,h,_,k)=>{[d.el,d.anchor]=v(d.children,h,_,k,d.el,d.anchor)},g=({el:d,anchor:h},_,k)=>{let P;for(;d&&d!==h;)P=p(d),r(d,_,k),d=P;r(h,_,k)},b=({el:d,anchor:h})=>{let _;for(;d&&d!==h;)_=p(d),o(d),d=_;o(h)},V=(d,h,_,k,P,A,F,N,$)=>{h.type==="svg"?F="svg":h.type==="math"&&(F="mathml"),d==null?q(h,_,k,P,A,F,N,$):z(d,h,P,A,F,N,$)},q=(d,h,_,k,P,A,F,N)=>{let $,R;const{props:Z,shapeFlag:G,transition:Q,dirs:ne}=d;if($=d.el=i(d.type,A,Z&&Z.is,Z),G&8?u($,d.children):G&16&&w(d.children,$,null,k,P,_o(d,A),F,N),ne&>(d,null,k,"created"),D($,d,d.scopeId,F,k),Z){for(const ye in Z)ye!=="value"&&!En(ye)&&s($,ye,null,Z[ye],A,k);"value"in Z&&s($,"value",null,Z.value,A),(R=Z.onVnodeBeforeMount)&&st(R,k,d)}ne&>(d,null,k,"beforeMount");const ae=Bl(P,Q);ae&&Q.beforeEnter($),r($,h,_),((R=Z&&Z.onVnodeMounted)||ae||ne)&&tt(()=>{R&&st(R,k,d),ae&&Q.enter($),ne&>(d,null,k,"mounted")},P)},D=(d,h,_,k,P)=>{if(_&&m(d,_),k)for(let A=0;A{for(let R=$;R{const N=h.el=d.el;let{patchFlag:$,dynamicChildren:R,dirs:Z}=h;$|=d.patchFlag&16;const G=d.props||_e,Q=h.props||_e;let ne;if(_&&Jt(_,!1),(ne=Q.onVnodeBeforeUpdate)&&st(ne,_,h,d),Z&>(h,d,_,"beforeUpdate"),_&&Jt(_,!0),(G.innerHTML&&Q.innerHTML==null||G.textContent&&Q.textContent==null)&&u(N,""),R?x(d.dynamicChildren,R,N,_,k,_o(h,P),A):F||W(d,h,N,null,_,k,_o(h,P),A,!1),$>0){if($&16)j(N,G,Q,_,P);else if($&2&&G.class!==Q.class&&s(N,"class",null,Q.class,P),$&4&&s(N,"style",G.style,Q.style,P),$&8){const ae=h.dynamicProps;for(let ye=0;ye{ne&&st(ne,_,h,d),Z&>(h,d,_,"updated")},k)},x=(d,h,_,k,P,A,F)=>{for(let N=0;N{if(h!==_){if(h!==_e)for(const A in h)!En(A)&&!(A in _)&&s(d,A,h[A],null,P,k);for(const A in _){if(En(A))continue;const F=_[A],N=h[A];F!==N&&A!=="value"&&s(d,A,N,F,P,k)}"value"in _&&s(d,"value",h.value,_.value,P)}},E=(d,h,_,k,P,A,F,N,$)=>{const R=h.el=d?d.el:l(""),Z=h.anchor=d?d.anchor:l("");let{patchFlag:G,dynamicChildren:Q,slotScopeIds:ne}=h;ne&&(N=N?N.concat(ne):ne),d==null?(r(R,_,k),r(Z,_,k),w(h.children||[],_,Z,P,A,F,N,$)):G>0&&G&64&&Q&&d.dynamicChildren?(x(d.dynamicChildren,Q,_,P,A,F,N),(h.key!=null||P&&h===P.subTree)&&Fl(d,h,!0)):W(d,h,_,Z,P,A,F,N,$)},M=(d,h,_,k,P,A,F,N,$)=>{h.slotScopeIds=N,d==null?h.shapeFlag&512?P.ctx.activate(h,_,k,F,$):X(h,_,k,P,A,F,$):ie(d,h,$)},X=(d,h,_,k,P,A,F)=>{const N=d.component=zu(d,k,P);if(ur(d)&&(N.ctx.renderer=Y),Uu(N,!1,F),N.asyncDep){if(P&&P.registerDep(N,I,F),!d.el){const $=N.subTree=se(Be);T(null,$,h,_)}}else I(N,d,h,_,P,A,F)},ie=(d,h,_)=>{const k=h.component=d.component;if(Du(d,h,_))if(k.asyncDep&&!k.asyncResolved){J(k,h,_);return}else k.next=h,k.update();else h.el=d.el,k.vnode=h},I=(d,h,_,k,P,A,F)=>{const N=()=>{if(d.isMounted){let{next:G,bu:Q,u:ne,parent:ae,vnode:ye}=d;{const Ze=zl(d);if(Ze){G&&(G.el=ye.el,J(d,G,F)),Ze.asyncDep.then(()=>{d.isUnmounted||N()});return}}let de=G,Xe;Jt(d,!1),G?(G.el=ye.el,J(d,G,F)):G=ye,Q&&co(Q),(Xe=G.props&&G.props.onVnodeBeforeUpdate)&&st(Xe,ae,G,ye),Jt(d,!0);const Ne=bo(d),at=d.subTree;d.subTree=Ne,y(at,Ne,c(at.el),L(at),d,P,A),G.el=Ne.el,de===null&&Mu(d,Ne.el),ne&&tt(ne,P),(Xe=G.props&&G.props.onVnodeUpdated)&&tt(()=>st(Xe,ae,G,ye),P)}else{let G;const{el:Q,props:ne}=h,{bm:ae,m:ye,parent:de,root:Xe,type:Ne}=d,at=ln(h);if(Jt(d,!1),ae&&co(ae),!at&&(G=ne&&ne.onVnodeBeforeMount)&&st(G,de,h),Jt(d,!0),Q&&he){const Ze=()=>{d.subTree=bo(d),he(Q,d.subTree,d,P,null)};at&&Ne.__asyncHydrate?Ne.__asyncHydrate(Q,d,Ze):Ze()}else{Xe.ce&&Xe.ce._injectChildStyle(Ne);const Ze=d.subTree=bo(d);y(null,Ze,_,k,d,P,A),h.el=Ze.el}if(ye&&tt(ye,P),!at&&(G=ne&&ne.onVnodeMounted)){const Ze=h;tt(()=>st(G,de,Ze),P)}(h.shapeFlag&256||de&&ln(de.vnode)&&de.vnode.shapeFlag&256)&&d.a&&tt(d.a,P),d.isMounted=!0,h=_=k=null}};d.scope.on();const $=d.effect=new Qi(N);d.scope.off();const R=d.update=$.run.bind($),Z=d.job=$.runIfDirty.bind($);Z.i=d,Z.id=d.uid,$.scheduler=()=>ss(Z),Jt(d,!0),R()},J=(d,h,_)=>{h.component=d;const k=d.vnode.props;d.vnode=h,d.next=null,vu(d,h.props,k,_),Eu(d,h.children,_),Kt(),Ms(d),Gt()},W=(d,h,_,k,P,A,F,N,$=!1)=>{const R=d&&d.children,Z=d?d.shapeFlag:0,G=h.children,{patchFlag:Q,shapeFlag:ne}=h;if(Q>0){if(Q&128){He(R,G,_,k,P,A,F,N,$);return}else if(Q&256){be(R,G,_,k,P,A,F,N,$);return}}ne&8?(Z&16&&Je(R,P,A),G!==R&&u(_,G)):Z&16?ne&16?He(R,G,_,k,P,A,F,N,$):Je(R,P,A,!0):(Z&8&&u(_,""),ne&16&&w(G,_,k,P,A,F,N,$))},be=(d,h,_,k,P,A,F,N,$)=>{d=d||bn,h=h||bn;const R=d.length,Z=h.length,G=Math.min(R,Z);let Q;for(Q=0;QZ?Je(d,P,A,!0,!1,G):w(h,_,k,P,A,F,N,$,G)},He=(d,h,_,k,P,A,F,N,$)=>{let R=0;const Z=h.length;let G=d.length-1,Q=Z-1;for(;R<=G&&R<=Q;){const ne=d[R],ae=h[R]=$?$t(h[R]):it(h[R]);if(nn(ne,ae))y(ne,ae,_,null,P,A,F,N,$);else break;R++}for(;R<=G&&R<=Q;){const ne=d[G],ae=h[Q]=$?$t(h[Q]):it(h[Q]);if(nn(ne,ae))y(ne,ae,_,null,P,A,F,N,$);else break;G--,Q--}if(R>G){if(R<=Q){const ne=Q+1,ae=neQ)for(;R<=G;)$e(d[R],P,A,!0),R++;else{const ne=R,ae=R,ye=new Map;for(R=ae;R<=Q;R++){const et=h[R]=$?$t(h[R]):it(h[R]);et.key!=null&&ye.set(et.key,R)}let de,Xe=0;const Ne=Q-ae+1;let at=!1,Ze=0;const In=new Array(Ne);for(R=0;R=Ne){$e(et,P,A,!0);continue}let ht;if(et.key!=null)ht=ye.get(et.key);else for(de=ae;de<=Q;de++)if(In[de-ae]===0&&nn(et,h[de])){ht=de;break}ht===void 0?$e(et,P,A,!0):(In[ht-ae]=R+1,ht>=Ze?Ze=ht:at=!0,y(et,h[ht],_,null,P,A,F,N,$),Xe++)}const Ls=at?Pu(In):bn;for(de=Ls.length-1,R=Ne-1;R>=0;R--){const et=ae+R,ht=h[et],Cs=et+1{const{el:A,type:F,transition:N,children:$,shapeFlag:R}=d;if(R&6){Ye(d.component.subTree,h,_,k);return}if(R&128){d.suspense.move(h,_,k);return}if(R&64){F.move(d,h,_,Y);return}if(F===me){r(A,h,_);for(let G=0;G<$.length;G++)Ye($[G],h,_,k);r(d.anchor,h,_);return}if(F===Pn){g(d,h,_);return}if(k!==2&&R&1&&N)if(k===0)N.beforeEnter(A),r(A,h,_),tt(()=>N.enter(A),P);else{const{leave:G,delayLeave:Q,afterLeave:ne}=N,ae=()=>r(A,h,_),ye=()=>{G(A,()=>{ae(),ne&&ne()})};Q?Q(A,ae,ye):ye()}else r(A,h,_)},$e=(d,h,_,k=!1,P=!1)=>{const{type:A,props:F,ref:N,children:$,dynamicChildren:R,shapeFlag:Z,patchFlag:G,dirs:Q,cacheIndex:ne}=d;if(G===-2&&(P=!1),N!=null&&Nr(N,null,_,d,!0),ne!=null&&(h.renderCache[ne]=void 0),Z&256){h.ctx.deactivate(d);return}const ae=Z&1&&Q,ye=!ln(d);let de;if(ye&&(de=F&&F.onVnodeBeforeUnmount)&&st(de,h,d),Z&6)pt(d.component,_,k);else{if(Z&128){d.suspense.unmount(_,k);return}ae&>(d,null,h,"beforeUnmount"),Z&64?d.type.remove(d,h,_,Y,k):R&&!R.hasOnce&&(A!==me||G>0&&G&64)?Je(R,h,_,!1,!0):(A===me&&G&384||!P&&Z&16)&&Je($,h,_),k&&Ot(d)}(ye&&(de=F&&F.onVnodeUnmounted)||ae)&&tt(()=>{de&&st(de,h,d),ae&>(d,null,h,"unmounted")},_)},Ot=d=>{const{type:h,el:_,anchor:k,transition:P}=d;if(h===me){Rt(_,k);return}if(h===Pn){b(d);return}const A=()=>{o(_),P&&!P.persisted&&P.afterLeave&&P.afterLeave()};if(d.shapeFlag&1&&P&&!P.persisted){const{leave:F,delayLeave:N}=P,$=()=>F(_,A);N?N(d.el,A,$):$()}else A()},Rt=(d,h)=>{let _;for(;d!==h;)_=p(d),o(d),d=_;o(h)},pt=(d,h,_)=>{const{bum:k,scope:P,job:A,subTree:F,um:N,m:$,a:R}=d;Ws($),Ws(R),k&&co(k),P.stop(),A&&(A.flags|=8,$e(F,d,h,_)),N&&tt(N,h),tt(()=>{d.isUnmounted=!0},h),h&&h.pendingBranch&&!h.isUnmounted&&d.asyncDep&&!d.asyncResolved&&d.suspenseId===h.pendingId&&(h.deps--,h.deps===0&&h.resolve())},Je=(d,h,_,k=!1,P=!1,A=0)=>{for(let F=A;F{if(d.shapeFlag&6)return L(d.component.subTree);if(d.shapeFlag&128)return d.suspense.next();const h=p(d.anchor||d.el),_=h&&h[Fc];return _?p(_):h};let U=!1;const B=(d,h,_)=>{d==null?h._vnode&&$e(h._vnode,null,null,!0):y(h._vnode||null,d,h,null,null,null,_),h._vnode=d,U||(U=!0,Ms(),Vr(),U=!1)},Y={p:y,um:$e,m:Ye,r:Ot,mt:X,mc:w,pc:W,pbc:x,n:L,o:e};let le,he;return t&&([le,he]=t(Y)),{render:B,hydrate:le,createApp:mu(B,le)}}function _o({type:e,props:t},n){return n==="svg"&&e==="foreignObject"||n==="mathml"&&e==="annotation-xml"&&t&&t.encoding&&t.encoding.includes("html")?void 0:n}function Jt({effect:e,job:t},n){n?(e.flags|=32,t.flags|=4):(e.flags&=-33,t.flags&=-5)}function Bl(e,t){return(!e||e&&!e.pendingBranch)&&t&&!t.persisted}function Fl(e,t,n=!1){const r=e.children,o=t.children;if(te(r)&&te(o))for(let s=0;s>1,e[n[l]]0&&(t[r]=n[s-1]),n[s]=r)}}for(s=n.length,i=n[s-1];s-- >0;)n[s]=i,i=t[i];return n}function zl(e){const t=e.subTree.component;if(t)return t.asyncDep&&!t.asyncResolved?t:zl(t)}function Ws(e){if(e)for(let t=0;tFe(xu);function Cu(e,t){return eo(e,null,t)}function Tu(e,t){return eo(e,null,{flush:"post"})}function ze(e,t,n){return eo(e,t,n)}function eo(e,t,n=_e){const{immediate:r,deep:o,flush:s,once:i}=n,l=Re({},n);let a;if(hr)if(s==="sync"){const p=Lu();a=p.__watcherHandles||(p.__watcherHandles=[])}else if(!t||r)l.once=!0;else{const p=()=>{};return p.stop=vt,p.resume=vt,p.pause=vt,p}const f=De;l.call=(p,m,v)=>ft(p,f,m,v);let u=!1;s==="post"?l.scheduler=p=>{tt(p,f&&f.suspense)}:s!=="sync"&&(u=!0,l.scheduler=(p,m)=>{m?p():ss(p)}),l.augmentJob=p=>{t&&(p.flags|=4),u&&(p.flags|=2,f&&(p.id=f.uid,p.i=f))};const c=$c(e,t,l);return a&&a.push(c),c}function ku(e,t,n){const r=this.proxy,o=Te(e)?e.includes(".")?Ul(r,e):()=>r[e]:e.bind(r,r);let s;oe(t)?s=t:(s=t.handler,n=t);const i=pr(this),l=eo(o,s.bind(r),n);return i(),l}function Ul(e,t){const n=t.split(".");return()=>{let r=e;for(let o=0;ot==="modelValue"||t==="model-value"?e.modelModifiers:e[`${t}Modifiers`]||e[`${rt(t)}Modifiers`]||e[`${Wt(t)}Modifiers`];function Ou(e,t,...n){if(e.isUnmounted)return;const r=e.vnode.props||_e;let o=n;const s=t.startsWith("update:"),i=s&&Au(r,t.slice(7));i&&(i.trim&&(o=n.map(u=>Te(u)?u.trim():u)),i.number&&(o=n.map(Ya)));let l,a=r[l=ao(t)]||r[l=ao(rt(t))];!a&&s&&(a=r[l=ao(Wt(t))]),a&&ft(a,e,6,o);const f=r[l+"Once"];if(f){if(!e.emitted)e.emitted={};else if(e.emitted[l])return;e.emitted[l]=!0,ft(f,e,6,o)}}function Wl(e,t,n=!1){const r=t.emitsCache,o=r.get(e);if(o!==void 0)return o;const s=e.emits;let i={},l=!1;if(!oe(e)){const a=f=>{const u=Wl(f,t,!0);u&&(l=!0,Re(i,u))};!n&&t.mixins.length&&t.mixins.forEach(a),e.extends&&a(e.extends),e.mixins&&e.mixins.forEach(a)}return!s&&!l?(Ee(e)&&r.set(e,null),null):(te(s)?s.forEach(a=>i[a]=null):Re(i,s),Ee(e)&&r.set(e,i),i)}function to(e,t){return!e||!or(t)?!1:(t=t.slice(2).replace(/Once$/,""),ue(e,t[0].toLowerCase()+t.slice(1))||ue(e,Wt(t))||ue(e,t))}function bo(e){const{type:t,vnode:n,proxy:r,withProxy:o,propsOptions:[s],slots:i,attrs:l,emit:a,render:f,renderCache:u,props:c,data:p,setupState:m,ctx:v,inheritAttrs:y}=e,C=Hr(e);let T,S;try{if(n.shapeFlag&4){const b=o||r,V=b;T=it(f.call(V,b,u,c,m,p,v)),S=l}else{const b=t;T=it(b.length>1?b(c,{attrs:l,slots:i,emit:a}):b(c,null)),S=t.props?l:Ru(l)}}catch(b){zn.length=0,cr(b,e,1),T=se(Be)}let g=T;if(S&&y!==!1){const b=Object.keys(S),{shapeFlag:V}=g;b.length&&V&7&&(s&&b.some(Go)&&(S=Iu(S,s)),g=Ft(g,S,!1,!0))}return n.dirs&&(g=Ft(g,null,!1,!0),g.dirs=g.dirs?g.dirs.concat(n.dirs):n.dirs),n.transition&&Qn(g,n.transition),T=g,Hr(C),T}const Ru=e=>{let t;for(const n in e)(n==="class"||n==="style"||or(n))&&((t||(t={}))[n]=e[n]);return t},Iu=(e,t)=>{const n={};for(const r in e)(!Go(r)||!(r.slice(9)in t))&&(n[r]=e[r]);return n};function Du(e,t,n){const{props:r,children:o,component:s}=e,{props:i,children:l,patchFlag:a}=t,f=s.emitsOptions;if(t.dirs||t.transition)return!0;if(n&&a>=0){if(a&1024)return!0;if(a&16)return r?Ks(r,i,f):!!i;if(a&8){const u=t.dynamicProps;for(let c=0;ce.__isSuspense;function Gl(e,t){t&&t.pendingBranch?te(e)?t.effects.push(...e):t.effects.push(e):Bc(e)}const me=Symbol.for("v-fgt"),cn=Symbol.for("v-txt"),Be=Symbol.for("v-cmt"),Pn=Symbol.for("v-stc"),zn=[];let nt=null;function K(e=!1){zn.push(nt=e?null:[])}function Vu(){zn.pop(),nt=zn[zn.length-1]||null}let Xn=1;function Gs(e){Xn+=e,e<0&&nt&&(nt.hasOnce=!0)}function ql(e){return e.dynamicChildren=Xn>0?nt||bn:null,Vu(),Xn>0&&nt&&nt.push(e),e}function ee(e,t,n,r,o,s){return ql(re(e,t,n,r,o,s,!0))}function Ce(e,t,n,r,o){return ql(se(e,t,n,r,o,!0))}function Br(e){return e?e.__v_isVNode===!0:!1}function nn(e,t){return e.type===t.type&&e.key===t.key}const Yl=({key:e})=>e??null,Ar=({ref:e,ref_key:t,ref_for:n})=>(typeof e=="number"&&(e=""+e),e!=null?Te(e)||Oe(e)||oe(e)?{i:Me,r:e,k:t,f:!!n}:e:null);function re(e,t=null,n=null,r=0,o=null,s=e===me?0:1,i=!1,l=!1){const a={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&Yl(t),ref:t&&Ar(t),scopeId:bl,slotScopeIds:null,children:n,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetStart:null,targetAnchor:null,staticCount:0,shapeFlag:s,patchFlag:r,dynamicProps:o,dynamicChildren:null,appContext:null,ctx:Me};return l?(fs(a,n),s&128&&e.normalize(a)):n&&(a.shapeFlag|=Te(n)?8:16),Xn>0&&!i&&nt&&(a.patchFlag>0||s&6)&&a.patchFlag!==32&&nt.push(a),a}const se=Hu;function Hu(e,t=null,n=null,r=0,o=null,s=!1){if((!e||e===iu)&&(e=Be),Br(e)){const l=Ft(e,t,!0);return n&&fs(l,n),Xn>0&&!s&&nt&&(l.shapeFlag&6?nt[nt.indexOf(e)]=l:nt.push(l)),l.patchFlag=-2,l}if(Yu(e)&&(e=e.__vccOpts),t){t=$u(t);let{class:l,style:a}=t;l&&!Te(l)&&(t.class=Qe(l)),Ee(a)&&(ns(a)&&!te(a)&&(a=Re({},a)),t.style=ir(a))}const i=Te(e)?1:Kl(e)?128:yl(e)?64:Ee(e)?4:oe(e)?2:0;return re(e,t,n,r,o,i,s,!0)}function $u(e){return e?ns(e)||Dl(e)?Re({},e):e:null}function Ft(e,t,n=!1,r=!1){const{props:o,ref:s,patchFlag:i,children:l,transition:a}=e,f=t?ju(o||{},t):o,u={__v_isVNode:!0,__v_skip:!0,type:e.type,props:f,key:f&&Yl(f),ref:t&&t.ref?n&&s?te(s)?s.concat(Ar(t)):[s,Ar(t)]:Ar(t):s,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:l,target:e.target,targetStart:e.targetStart,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==me?i===-1?16:i|16:i,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:a,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&Ft(e.ssContent),ssFallback:e.ssFallback&&Ft(e.ssFallback),el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce};return a&&r&&Qn(u,a.clone(u)),u}function zt(e=" ",t=0){return se(cn,null,e,t)}function Nu(e,t){const n=se(Pn,null,e);return n.staticCount=t,n}function Ae(e="",t=!1){return t?(K(),Ce(Be,null,e)):se(Be,null,e)}function it(e){return e==null||typeof e=="boolean"?se(Be):te(e)?se(me,null,e.slice()):typeof e=="object"?$t(e):se(cn,null,String(e))}function $t(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:Ft(e)}function fs(e,t){let n=0;const{shapeFlag:r}=e;if(t==null)t=null;else if(te(t))n=16;else if(typeof t=="object")if(r&65){const o=t.default;o&&(o._c&&(o._d=!1),fs(e,o()),o._c&&(o._d=!0));return}else{n=32;const o=t._;!o&&!Dl(t)?t._ctx=Me:o===3&&Me&&(Me.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else oe(t)?(t={default:t,_ctx:Me},n=32):(t=String(t),r&64?(n=16,t=[zt(t)]):n=8);e.children=t,e.shapeFlag|=n}function ju(...e){const t={};for(let n=0;nDe||Me;let Fr,Ho;{const e=Ki(),t=(n,r)=>{let o;return(o=e[n])||(o=e[n]=[]),o.push(r),s=>{o.length>1?o.forEach(i=>i(s)):o[0](s)}};Fr=t("__VUE_INSTANCE_SETTERS__",n=>De=n),Ho=t("__VUE_SSR_SETTERS__",n=>hr=n)}const pr=e=>{const t=De;return Fr(e),e.scope.on(),()=>{e.scope.off(),Fr(t)}},qs=()=>{De&&De.scope.off(),Fr(null)};function Jl(e){return e.vnode.shapeFlag&4}let hr=!1;function Uu(e,t=!1,n=!1){t&&Ho(t);const{props:r,children:o}=e.vnode,s=Jl(e);gu(e,r,s,t),yu(e,o,n);const i=s?Wu(e,t):void 0;return t&&Ho(!1),i}function Wu(e,t){const n=e.type;e.accessCache=Object.create(null),e.proxy=new Proxy(e.ctx,au);const{setup:r}=n;if(r){const o=e.setupContext=r.length>1?Gu(e):null,s=pr(e);Kt();const i=ar(r,e,0,[e.props,o]);if(Gt(),s(),Fi(i)){if(ln(e)||is(e),i.then(qs,qs),t)return i.then(l=>{Ys(e,l,t)}).catch(l=>{cr(l,e,0)});e.asyncDep=i}else Ys(e,i,t)}else Ql(e,t)}function Ys(e,t,n){oe(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:Ee(t)&&(e.setupState=pl(t)),Ql(e,n)}let Js;function Ql(e,t,n){const r=e.type;if(!e.render){if(!t&&Js&&!r.render){const o=r.template||cs(e).template;if(o){const{isCustomElement:s,compilerOptions:i}=e.appContext.config,{delimiters:l,compilerOptions:a}=r,f=Re(Re({isCustomElement:s,delimiters:l},i),a);r.render=Js(o,f)}}e.render=r.render||vt}{const o=pr(e);Kt();try{cu(e)}finally{Gt(),o()}}}const Ku={get(e,t){return Ue(e,"get",""),e[t]}};function Gu(e){const t=n=>{e.exposed=n||{}};return{attrs:new Proxy(e.attrs,Ku),slots:e.slots,emit:e.emit,expose:t}}function no(e){return e.exposed?e.exposeProxy||(e.exposeProxy=new Proxy(pl(Cc(e.exposed)),{get(t,n){if(n in t)return t[n];if(n in Fn)return Fn[n](e)},has(t,n){return n in t||n in Fn}})):e.proxy}function qu(e,t=!0){return oe(e)?e.displayName||e.name:e.name||t&&e.__name}function Yu(e){return oe(e)&&"__vccOpts"in e}const H=(e,t)=>Vc(e,t,hr);function Ve(e,t,n){const r=arguments.length;return r===2?Ee(t)&&!te(t)?Br(t)?se(e,null,[t]):se(e,t):se(e,null,t):(r>3?n=Array.prototype.slice.call(arguments,2):r===3&&Br(n)&&(n=[n]),se(e,t,n))}const Ju="3.5.8";/** +* @vue/runtime-dom v3.5.8 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/let $o;const Qs=typeof window<"u"&&window.trustedTypes;if(Qs)try{$o=Qs.createPolicy("vue",{createHTML:e=>e})}catch{}const Xl=$o?e=>$o.createHTML(e):e=>e,Qu="http://www.w3.org/2000/svg",Xu="http://www.w3.org/1998/Math/MathML",Lt=typeof document<"u"?document:null,Xs=Lt&&Lt.createElement("template"),Zu={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,r)=>{const o=t==="svg"?Lt.createElementNS(Qu,e):t==="mathml"?Lt.createElementNS(Xu,e):n?Lt.createElement(e,{is:n}):Lt.createElement(e);return e==="select"&&r&&r.multiple!=null&&o.setAttribute("multiple",r.multiple),o},createText:e=>Lt.createTextNode(e),createComment:e=>Lt.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>Lt.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,r,o,s){const i=n?n.previousSibling:t.lastChild;if(o&&(o===s||o.nextSibling))for(;t.insertBefore(o.cloneNode(!0),n),!(o===s||!(o=o.nextSibling)););else{Xs.innerHTML=Xl(r==="svg"?`${e}`:r==="mathml"?`${e}`:e);const l=Xs.content;if(r==="svg"||r==="mathml"){const a=l.firstChild;for(;a.firstChild;)l.appendChild(a.firstChild);l.removeChild(a)}t.insertBefore(l,n)}return[i?i.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}},Dt="transition",Mn="animation",Zn=Symbol("_vtc"),Zl={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String},ef=Re({},El,Zl),tf=e=>(e.displayName="Transition",e.props=ef,e),ea=tf((e,{slots:t})=>Ve(Wc,nf(e),t)),Qt=(e,t=[])=>{te(e)?e.forEach(n=>n(...t)):e&&e(...t)},Zs=e=>e?te(e)?e.some(t=>t.length>1):e.length>1:!1;function nf(e){const t={};for(const E in e)E in Zl||(t[E]=e[E]);if(e.css===!1)return t;const{name:n="v",type:r,duration:o,enterFromClass:s=`${n}-enter-from`,enterActiveClass:i=`${n}-enter-active`,enterToClass:l=`${n}-enter-to`,appearFromClass:a=s,appearActiveClass:f=i,appearToClass:u=l,leaveFromClass:c=`${n}-leave-from`,leaveActiveClass:p=`${n}-leave-active`,leaveToClass:m=`${n}-leave-to`}=e,v=rf(o),y=v&&v[0],C=v&&v[1],{onBeforeEnter:T,onEnter:S,onEnterCancelled:g,onLeave:b,onLeaveCancelled:V,onBeforeAppear:q=T,onAppear:D=S,onAppearCancelled:w=g}=t,z=(E,M,X)=>{Xt(E,M?u:l),Xt(E,M?f:i),X&&X()},x=(E,M)=>{E._isLeaving=!1,Xt(E,c),Xt(E,m),Xt(E,p),M&&M()},j=E=>(M,X)=>{const ie=E?D:S,I=()=>z(M,E,X);Qt(ie,[M,I]),ei(()=>{Xt(M,E?a:s),Mt(M,E?u:l),Zs(ie)||ti(M,r,y,I)})};return Re(t,{onBeforeEnter(E){Qt(T,[E]),Mt(E,s),Mt(E,i)},onBeforeAppear(E){Qt(q,[E]),Mt(E,a),Mt(E,f)},onEnter:j(!1),onAppear:j(!0),onLeave(E,M){E._isLeaving=!0;const X=()=>x(E,M);Mt(E,c),Mt(E,p),lf(),ei(()=>{E._isLeaving&&(Xt(E,c),Mt(E,m),Zs(b)||ti(E,r,C,X))}),Qt(b,[E,X])},onEnterCancelled(E){z(E,!1),Qt(g,[E])},onAppearCancelled(E){z(E,!0),Qt(w,[E])},onLeaveCancelled(E){x(E),Qt(V,[E])}})}function rf(e){if(e==null)return null;if(Ee(e))return[yo(e.enter),yo(e.leave)];{const t=yo(e);return[t,t]}}function yo(e){return Ja(e)}function Mt(e,t){t.split(/\s+/).forEach(n=>n&&e.classList.add(n)),(e[Zn]||(e[Zn]=new Set)).add(t)}function Xt(e,t){t.split(/\s+/).forEach(r=>r&&e.classList.remove(r));const n=e[Zn];n&&(n.delete(t),n.size||(e[Zn]=void 0))}function ei(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let of=0;function ti(e,t,n,r){const o=e._endId=++of,s=()=>{o===e._endId&&r()};if(n!=null)return setTimeout(s,n);const{type:i,timeout:l,propCount:a}=sf(e,t);if(!i)return r();const f=i+"end";let u=0;const c=()=>{e.removeEventListener(f,p),s()},p=m=>{m.target===e&&++u>=a&&c()};setTimeout(()=>{u(n[v]||"").split(", "),o=r(`${Dt}Delay`),s=r(`${Dt}Duration`),i=ni(o,s),l=r(`${Mn}Delay`),a=r(`${Mn}Duration`),f=ni(l,a);let u=null,c=0,p=0;t===Dt?i>0&&(u=Dt,c=i,p=s.length):t===Mn?f>0&&(u=Mn,c=f,p=a.length):(c=Math.max(i,f),u=c>0?i>f?Dt:Mn:null,p=u?u===Dt?s.length:a.length:0);const m=u===Dt&&/\b(transform|all)(,|$)/.test(r(`${Dt}Property`).toString());return{type:u,timeout:c,propCount:p,hasTransform:m}}function ni(e,t){for(;e.lengthri(n)+ri(e[r])))}function ri(e){return e==="auto"?0:Number(e.slice(0,-1).replace(",","."))*1e3}function lf(){return document.body.offsetHeight}function af(e,t,n){const r=e[Zn];r&&(t=(t?[t,...r]:[...r]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}const zr=Symbol("_vod"),ta=Symbol("_vsh"),Ur={beforeMount(e,{value:t},{transition:n}){e[zr]=e.style.display==="none"?"":e.style.display,n&&t?n.beforeEnter(e):Vn(e,t)},mounted(e,{value:t},{transition:n}){n&&t&&n.enter(e)},updated(e,{value:t,oldValue:n},{transition:r}){!t!=!n&&(r?t?(r.beforeEnter(e),Vn(e,!0),r.enter(e)):r.leave(e,()=>{Vn(e,!1)}):Vn(e,t))},beforeUnmount(e,{value:t}){Vn(e,t)}};function Vn(e,t){e.style.display=t?e[zr]:"none",e[ta]=!t}const na=Symbol("");function $v(e){const t=dr();if(!t)return;const n=t.ut=(o=e(t.proxy))=>{Array.from(document.querySelectorAll(`[data-v-owner="${t.uid}"]`)).forEach(s=>Wr(s,o))},r=()=>{const o=e(t.proxy);t.ce?Wr(t.ce,o):No(t.subTree,o),n(o)};Cl(()=>{Tu(r)}),We(()=>{const o=new MutationObserver(r);o.observe(t.subTree.el.parentNode,{childList:!0}),fr(()=>o.disconnect())})}function No(e,t){if(e.shapeFlag&128){const n=e.suspense;e=n.activeBranch,n.pendingBranch&&!n.isHydrating&&n.effects.push(()=>{No(n.activeBranch,t)})}for(;e.component;)e=e.component.subTree;if(e.shapeFlag&1&&e.el)Wr(e.el,t);else if(e.type===me)e.children.forEach(n=>No(n,t));else if(e.type===Pn){let{el:n,anchor:r}=e;for(;n&&(Wr(n,t),n!==r);)n=n.nextSibling}}function Wr(e,t){if(e.nodeType===1){const n=e.style;let r="";for(const o in t)n.setProperty(`--${o}`,t[o]),r+=`--${o}: ${t[o]};`;n[na]=r}}const cf=/(^|;)\s*display\s*:/;function uf(e,t,n){const r=e.style,o=Te(n);let s=!1;if(n&&!o){if(t)if(Te(t))for(const i of t.split(";")){const l=i.slice(0,i.indexOf(":")).trim();n[l]==null&&Or(r,l,"")}else for(const i in t)n[i]==null&&Or(r,i,"");for(const i in n)i==="display"&&(s=!0),Or(r,i,n[i])}else if(o){if(t!==n){const i=r[na];i&&(n+=";"+i),r.cssText=n,s=cf.test(n)}}else t&&e.removeAttribute("style");zr in e&&(e[zr]=s?r.display:"",e[ta]&&(r.display="none"))}const oi=/\s*!important$/;function Or(e,t,n){if(te(n))n.forEach(r=>Or(e,t,r));else if(n==null&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{const r=ff(e,t);oi.test(n)?e.setProperty(Wt(r),n.replace(oi,""),"important"):e[r]=n}}const si=["Webkit","Moz","ms"],Eo={};function ff(e,t){const n=Eo[t];if(n)return n;let r=rt(t);if(r!=="filter"&&r in e)return Eo[t]=r;r=sr(r);for(let o=0;owo||(vf.then(()=>wo=0),wo=Date.now());function bf(e,t){const n=r=>{if(!r._vts)r._vts=Date.now();else if(r._vts<=n.attached)return;ft(yf(r,n.value),t,5,[r])};return n.value=e,n.attached=_f(),n}function yf(e,t){if(te(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(r=>o=>!o._stopped&&r&&r(o))}else return t}const ui=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,Ef=(e,t,n,r,o,s)=>{const i=o==="svg";t==="class"?af(e,r,i):t==="style"?uf(e,n,r):or(t)?Go(t)||mf(e,t,n,r,s):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):wf(e,t,r,i))?(df(e,t,r),!e.tagName.includes("-")&&(t==="value"||t==="checked"||t==="selected")&&li(e,t,r,i,s,t!=="value")):(t==="true-value"?e._trueValue=r:t==="false-value"&&(e._falseValue=r),li(e,t,r,i))};function wf(e,t,n,r){if(r)return!!(t==="innerHTML"||t==="textContent"||t in e&&ui(t)&&oe(n));if(t==="spellcheck"||t==="draggable"||t==="translate"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA")return!1;if(t==="width"||t==="height"){const o=e.tagName;if(o==="IMG"||o==="VIDEO"||o==="CANVAS"||o==="SOURCE")return!1}return ui(t)&&Te(n)?!1:!!(t in e||e._isVueCE&&(/[A-Z]/.test(t)||!Te(n)))}const Sf={esc:"escape",space:" ",up:"arrow-up",left:"arrow-left",right:"arrow-right",down:"arrow-down",delete:"backspace"},Pf=(e,t)=>{const n=e._withKeys||(e._withKeys={}),r=t.join(".");return n[r]||(n[r]=o=>{if(!("key"in o))return;const s=Wt(o.key);if(t.some(i=>i===s||Sf[i]===s))return e(o)})},xf=Re({patchProp:Ef},Zu);let So,fi=!1;function Lf(){return So=fi?So:wu(xf),fi=!0,So}const Cf=(...e)=>{const t=Lf().createApp(...e),{mount:n}=t;return t.mount=r=>{const o=kf(r);if(o)return n(o,!0,Tf(o))},t};function Tf(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function kf(e){return Te(e)?document.querySelector(e):e}var mr=e=>/^[a-z][a-z0-9+.-]*:/.test(e)||e.startsWith("//"),Af=/.md((\?|#).*)?$/,Of=(e,t="/")=>mr(e)||e.startsWith("/")&&!e.startsWith(t)&&!Af.test(e),ro=e=>/^(https?:)?\/\//.test(e),di=e=>{if(!e||e.endsWith("/"))return e;let t=e.replace(/(^|\/)README.md$/i,"$1index.html");return t.endsWith(".md")?t=t.substring(0,t.length-3)+".html":t.endsWith(".html")||(t=t+".html"),t.endsWith("/index.html")&&(t=t.substring(0,t.length-10)),t},Rf="http://.",If=(e,t)=>{if(!e.startsWith("/")&&t){const n=t.slice(0,t.lastIndexOf("/"));return di(new URL(`${n}/${e}`,Rf).pathname)}return di(e)},Df=(e,t)=>{const n=Object.keys(e).sort((r,o)=>{const s=o.split("/").length-r.split("/").length;return s!==0?s:o.length-r.length});for(const r of n)if(t.startsWith(r))return r;return"/"},Mf=(e,t="/")=>{const n=e.replace(/^(?:https?:)?\/\/[^/]*/,"");return n.startsWith(t)?`/${n.slice(t.length)}`:n},Vf=/(#|\?)/,ra=e=>{const[t,...n]=e.split(Vf);return{pathname:t,hashAndQueries:n.join("")}},Hf=["link","meta","script","style","noscript","template"],$f=["title","base"],Nf=([e,t,n])=>$f.includes(e)?e:Hf.includes(e)?e==="meta"&&t.name?`${e}.${t.name}`:e==="template"&&t.id?`${e}.${t.id}`:JSON.stringify([e,Object.entries(t).map(([r,o])=>typeof o=="boolean"?o?[r,""]:null:[r,o]).filter(r=>r!=null).sort(([r],[o])=>r.localeCompare(o)),n]):null,jf=e=>{const t=new Set,n=[];return e.forEach(r=>{const o=Nf(r);o&&!t.has(o)&&(t.add(o),n.push(r))}),n},Bf=e=>e[e.length-1]==="/"||e.endsWith(".html")?e:`${e}/`,oa=e=>e[e.length-1]==="/"?e.slice(0,-1):e,ds=e=>e[0]==="/"?e.slice(1):e,ps=e=>Object.prototype.toString.call(e)==="[object Object]",ut=e=>typeof e=="string";const Ff="modulepreload",zf=function(e){return"/docs/"+e},pi={},O=function(t,n,r){let o=Promise.resolve();if(n&&n.length>0){document.getElementsByTagName("link");const i=document.querySelector("meta[property=csp-nonce]"),l=(i==null?void 0:i.nonce)||(i==null?void 0:i.getAttribute("nonce"));o=Promise.allSettled(n.map(a=>{if(a=zf(a),a in pi)return;pi[a]=!0;const f=a.endsWith(".css"),u=f?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${a}"]${u}`))return;const c=document.createElement("link");if(c.rel=f?"stylesheet":Ff,f||(c.as="script"),c.crossOrigin="",c.href=a,l&&c.setAttribute("nonce",l),document.head.appendChild(c),f)return new Promise((p,m)=>{c.addEventListener("load",p),c.addEventListener("error",()=>m(new Error(`Unable to preload CSS for ${a}`)))})}))}function s(i){const l=new Event("vite:preloadError",{cancelable:!0});if(l.payload=i,window.dispatchEvent(l),!l.defaultPrevented)throw i}return o.then(i=>{for(const l of i||[])l.status==="rejected"&&s(l.reason);return t().catch(s)})},Uf=JSON.parse('{"/_backlog-mermaid.html":"/backlog-mermaid.html","/_backlog.html":"/backlog.html","/_meta-test.html":"/meta-test.html"}'),Wf=Object.fromEntries([["/SUMMARY.html",{loader:()=>O(()=>import("./SUMMARY.html-o_nWAvKL.js"),[]),meta:{title:"Get Started"}}],["/backlog-mermaid.html",{loader:()=>O(()=>import("./backlog-mermaid.html-Baq9DOuh.js"),[]),meta:{title:""}}],["/backlog.html",{loader:()=>O(()=>import("./backlog.html-aIMMEHhy.js"),[]),meta:{title:"Documentation Backlog"}}],["/meta-test.html",{loader:()=>O(()=>import("./meta-test.html-Bv0TrQjv.js"),[]),meta:{title:""}}],["/component-compiler.html",{loader:()=>O(()=>import("./component-compiler.html-DQMaNo6k.js"),[]),meta:{title:"Automatic Component Generation"}}],["/component-reference.html",{loader:()=>O(()=>import("./component-reference.html-zo-jLPyy.js"),[]),meta:{title:"Needle Core Components"}}],["/debugging.html",{loader:()=>O(()=>import("./debugging.html-x99TIVp3.js"),[]),meta:{title:"How To Debug"}}],["/deployment.html",{loader:()=>O(()=>import("./deployment.html-C3wlSpNe.js"),__vite__mapDeps([0,1,2])),meta:{title:"Deployment and Optimization"}}],["/embedding.html",{loader:()=>O(()=>import("./embedding.html-Bwm82YNo.js"),[]),meta:{title:"Needle Engine on your Website"}}],["/everywhere-actions.html",{loader:()=>O(()=>import("./everywhere-actions.html-ddHbg6za.js"),[]),meta:{title:"Everywhere Actions"}}],["/examples.html",{loader:()=>O(()=>import("./examples.html-BMSngmVr.js"),[]),meta:{title:"Example Projects โœจ"}}],["/export.html",{loader:()=>O(()=>import("./export.html-Cyapuf2Z.js"),[]),meta:{title:"Exporting Assets to glTF"}}],["/faq.html",{loader:()=>O(()=>import("./faq.html-B6pZlv9Y.js"),__vite__mapDeps([3,2])),meta:{title:"Questions and Answers (FAQ) ๐Ÿ’ก"}}],["/features-overview.html",{loader:()=>O(()=>import("./features-overview.html-CBlEyL-B.js"),[]),meta:{title:"Feature Overview"}}],["/for-unity-developers.html",{loader:()=>O(()=>import("./for-unity-developers.html-Cn4ckO1w.js"),[]),meta:{title:"Scripting basics For Unity Developers"}}],["/getting-started.html",{loader:()=>O(()=>import("./getting-started.html-CpSyGMSg.js"),[]),meta:{title:""}}],["/html.html",{loader:()=>O(()=>import("./html.html-DP7Dz9Ne.js"),__vite__mapDeps([4,5])),meta:{title:"Frameworks, Bundlers, HTML"}}],["/",{loader:()=>O(()=>import("./index.html-CxWg-amX.js"),[]),meta:{title:""}}],["/modules.html",{loader:()=>O(()=>import("./modules.html-1xnFAmG8.js"),[]),meta:{title:"Additional Modules"}}],["/networking.html",{loader:()=>O(()=>import("./networking.html-Ccq0lod9.js"),[]),meta:{title:"Networking"}}],["/project-structure.html",{loader:()=>O(()=>import("./project-structure.html-DAYDA0w3.js"),[]),meta:{title:"Web Project Structure"}}],["/samples-and-modules.html",{loader:()=>O(()=>import("./samples-and-modules.html-BqywFF0Q.js"),[]),meta:{title:"Samples Projects"}}],["/scripting-examples.html",{loader:()=>O(()=>import("./scripting-examples.html-BShu_1Dw.js"),[]),meta:{title:"Scripting Examples"}}],["/scripting.html",{loader:()=>O(()=>import("./scripting.html-UnvL8K8f.js"),[]),meta:{title:"Creating and using Components"}}],["/showcase-bike.html",{loader:()=>O(()=>import("./showcase-bike.html-C8g9IaUw.js"),[]),meta:{title:"Bike Configurator ๐Ÿšฒ"}}],["/showcase-castle.html",{loader:()=>O(()=>import("./showcase-castle.html-2qaErZDl.js"),[]),meta:{title:"Castle Builder ๐Ÿฐ"}}],["/showcase-mercedes-benz.html",{loader:()=>O(()=>import("./showcase-mercedes-benz.html-CYMbPrd8.js"),[]),meta:{title:"Mercedes-Benz Showcase"}}],["/showcase-monsterhands.html",{loader:()=>O(()=>import("./showcase-monsterhands.html-Cjm5xxr6.js"),[]),meta:{title:"Monster Hands ๐Ÿ’€"}}],["/showcase-towerdefence.html",{loader:()=>O(()=>import("./showcase-towerdefence.html-B-3p76-5.js"),[]),meta:{title:"Tower Defense"}}],["/showcase-website.html",{loader:()=>O(()=>import("./showcase-website.html-DsWtTfPo.js"),[]),meta:{title:"Castle Builder ๐Ÿฐ"}}],["/showcase-zenrepublic.html",{loader:()=>O(()=>import("./showcase-zenrepublic.html-C8fRcD0r.js"),[]),meta:{title:"Monster Hands ๐Ÿ’€"}}],["/support.html",{loader:()=>O(()=>import("./support.html-g_P1G7eN.js"),[]),meta:{title:"Support and Community"}}],["/technical-overview.html",{loader:()=>O(()=>import("./technical-overview.html-BeSwd6Mh.js"),[]),meta:{title:"Technical Overview"}}],["/testimonials.html",{loader:()=>O(()=>import("./testimonials.html-B3wqsnkd.js"),[]),meta:{title:"Testimonials"}}],["/testing.html",{loader:()=>O(()=>import("./testing.html-DcypmV_S.js"),[]),meta:{title:"Testing on local devices"}}],["/vanilla-js.html",{loader:()=>O(()=>import("./vanilla-js.html-DtAi2Rtr.js"),[]),meta:{title:"Using Needle Engine directly from HTML"}}],["/vision.html",{loader:()=>O(()=>import("./vision.html-zI-oAntf.js"),[]),meta:{title:"Our Vision ๐Ÿ”ฎ"}}],["/xr.html",{loader:()=>O(()=>import("./xr.html-BFJdLi8t.js"),[]),meta:{title:"VR & AR (WebXR)"}}],["/blender/",{loader:()=>O(()=>import("./index.html-Ci232zr-.js"),__vite__mapDeps([6,1])),meta:{title:"Needle Engine for Blender"}}],["/custom-integrations/",{loader:()=>O(()=>import("./index.html-Msujlet7.js"),[]),meta:{title:"Integrate with other tools"}}],["/getting-started/for-unity-developers.html",{loader:()=>O(()=>import("./for-unity-developers.html-9HXvx0qv.js"),[]),meta:{title:"Scripting Introduction for Unity Developers"}}],["/getting-started/",{loader:()=>O(()=>import("./index.html-DyXM_9kx.js"),[]),meta:{title:"Getting Started & Installation"}}],["/getting-started/typescript-essentials.html",{loader:()=>O(()=>import("./typescript-essentials.html-B7bTUCZ9.js"),[]),meta:{title:"Scripting in Needle Engine"}}],["/reference/needle-config-json.html",{loader:()=>O(()=>import("./needle-config-json.html-CGJ-KXV-.js"),[]),meta:{title:"needle.config.json"}}],["/reference/needle-engine-attributes.html",{loader:()=>O(()=>import("./needle-engine-attributes.html-Dizdapts.js"),__vite__mapDeps([7,5])),meta:{title:" Configuration"}}],["/reference/typescript-decorators.html",{loader:()=>O(()=>import("./typescript-decorators.html-DQAWNuRE.js"),[]),meta:{title:"@serializable and other decorators"}}],["/three/",{loader:()=>O(()=>import("./index.html-_acHVPU1.js"),[]),meta:{title:"Needle Engine as Web Component"}}],["/unity/editor-sync.html",{loader:()=>O(()=>import("./editor-sync.html-B1ATYa5k.js"),[]),meta:{title:"Editor Sync"}}],["/unity/",{loader:()=>O(()=>import("./index.html-gQ6khto9.js"),[]),meta:{title:"Needle Engine for Unity"}}],["/404.html",{loader:()=>O(()=>import("./404.html-DQk9SM3x.js"),[]),meta:{title:""}}],["/community/contributions/llllkatjallll/custom-vr-button-that-appears-only-on-headsets-and-not-on-mobile-phones",{loader:()=>O(()=>import("./custom-vr-button-that-appears-only-on-headsets-and-not-on-mobile-phones.html-Cyk2JJNy.js"),[]),meta:{title:""}}],["/community/contributions/llllkatjallll/set-fallback-material-for-usdz-exporter",{loader:()=>O(()=>import("./set-fallback-material-for-usdz-exporter.html-BEiyoRdx.js"),[]),meta:{title:""}}],["/community/contributions/llllkatjallll",{loader:()=>O(()=>import("./llllkatjallll.html-CUXH6RfS.js"),[]),meta:{title:""}}],["/community/contributions/robyer1/microphone-access-in-a-browser-window-and-streamed-playback",{loader:()=>O(()=>import("./microphone-access-in-a-browser-window-and-streamed-playback.html-DC969LS3.js"),[]),meta:{title:""}}],["/community/contributions/robyer1/ar-move-scale-rotate-controls-for-needle-on-mobile",{loader:()=>O(()=>import("./ar-move-scale-rotate-controls-for-needle-on-mobile.html-CUtGjdNc.js"),[]),meta:{title:""}}],["/community/contributions/robyer1",{loader:()=>O(()=>import("./robyer1.html-DKUQa3GZ.js"),[]),meta:{title:""}}],["/community/contributions/ericcraft-mh/quicklook-vertical-image-tracker",{loader:()=>O(()=>import("./quicklook-vertical-image-tracker.html-C2obMcDm.js"),[]),meta:{title:""}}],["/community/contributions/ericcraft-mh",{loader:()=>O(()=>import("./ericcraft-mh.html-CjAn6AX_.js"),[]),meta:{title:""}}],["/community/contributions/krisrok/always-open-in-specific-browser",{loader:()=>O(()=>import("./always-open-in-specific-browser.html-Cboldk4x.js"),[]),meta:{title:""}}],["/community/contributions/krisrok",{loader:()=>O(()=>import("./krisrok.html-6_QA53zB.js"),[]),meta:{title:""}}],["/community/contributions/marwie/camera-video-background",{loader:()=>O(()=>import("./camera-video-background.html-BLeFh9kF.js"),[]),meta:{title:""}}],["/community/contributions/marwie/usdz-hide-object-on-start",{loader:()=>O(()=>import("./usdz-hide-object-on-start.html-Bd-eN8WF.js"),[]),meta:{title:""}}],["/community/contributions/marwie/everywhere-action-emphasize-on-click",{loader:()=>O(()=>import("./everywhere-action-emphasize-on-click.html-CVeSGZpb.js"),[]),meta:{title:""}}],["/community/contributions/marwie/control-a-timeline-by-scroll",{loader:()=>O(()=>import("./control-a-timeline-by-scroll.html-GAfS3g38.js"),[]),meta:{title:""}}],["/community/contributions/marwie/code-contribution-example",{loader:()=>O(()=>import("./code-contribution-example.html-BnLNxDrY.js"),[]),meta:{title:""}}],["/community/contributions/marwie",{loader:()=>O(()=>import("./marwie.html-DsbxB-fW.js"),[]),meta:{title:""}}],["/community/contributions/kipash/calculate-pointer-world-position",{loader:()=>O(()=>import("./calculate-pointer-world-position.html-BBtMcQ13.js"),[]),meta:{title:""}}],["/community/contributions/kipash",{loader:()=>O(()=>import("./kipash.html-BN1wH6PC.js"),[]),meta:{title:""}}],["/community/contributions/web3kev/vertical-move-in-vr-using-the-right-joystick-quest",{loader:()=>O(()=>import("./vertical-move-in-vr-using-the-right-joystick-quest.html-4yb7LuOj.js"),[]),meta:{title:""}}],["/community/contributions/web3kev/squeeze-to-scale-object-or-world-in-vr",{loader:()=>O(()=>import("./squeeze-to-scale-object-or-world-in-vr.html-C2ATGHYY.js"),[]),meta:{title:""}}],["/community/contributions/web3kev/network-instantiation-of-multiple-objects",{loader:()=>O(()=>import("./network-instantiation-of-multiple-objects.html-BiATyjwH.js"),[]),meta:{title:""}}],["/community/contributions/web3kev",{loader:()=>O(()=>import("./web3kev.html-BYOJlV9Z.js"),[]),meta:{title:""}}],["/community/contributions",{loader:()=>O(()=>import("./contributions.html-DddtFv1E.js"),[]),meta:{title:""}}]]);/*! + * vue-router v4.4.5 + * (c) 2024 Eduardo San Martin Morote + * @license MIT + */const vn=typeof document<"u";function sa(e){return typeof e=="object"||"displayName"in e||"props"in e||"__vccOpts"in e}function Kf(e){return e.__esModule||e[Symbol.toStringTag]==="Module"||e.default&&sa(e.default)}const pe=Object.assign;function Po(e,t){const n={};for(const r in t){const o=t[r];n[r]=dt(o)?o.map(e):e(o)}return n}const Un=()=>{},dt=Array.isArray,ia=/#/g,Gf=/&/g,qf=/\//g,Yf=/=/g,Jf=/\?/g,la=/\+/g,Qf=/%5B/g,Xf=/%5D/g,aa=/%5E/g,Zf=/%60/g,ca=/%7B/g,ed=/%7C/g,ua=/%7D/g,td=/%20/g;function hs(e){return encodeURI(""+e).replace(ed,"|").replace(Qf,"[").replace(Xf,"]")}function nd(e){return hs(e).replace(ca,"{").replace(ua,"}").replace(aa,"^")}function jo(e){return hs(e).replace(la,"%2B").replace(td,"+").replace(ia,"%23").replace(Gf,"%26").replace(Zf,"`").replace(ca,"{").replace(ua,"}").replace(aa,"^")}function rd(e){return jo(e).replace(Yf,"%3D")}function od(e){return hs(e).replace(ia,"%23").replace(Jf,"%3F")}function sd(e){return e==null?"":od(e).replace(qf,"%2F")}function er(e){try{return decodeURIComponent(""+e)}catch{}return""+e}const id=/\/$/,ld=e=>e.replace(id,"");function xo(e,t,n="/"){let r,o={},s="",i="";const l=t.indexOf("#");let a=t.indexOf("?");return l=0&&(a=-1),a>-1&&(r=t.slice(0,a),s=t.slice(a+1,l>-1?l:t.length),o=e(s)),l>-1&&(r=r||t.slice(0,l),i=t.slice(l,t.length)),r=fd(r??t,n),{fullPath:r+(s&&"?")+s+i,path:r,query:o,hash:er(i)}}function ad(e,t){const n=t.query?e(t.query):"";return t.path+(n&&"?")+n+(t.hash||"")}function hi(e,t){return!t||!e.toLowerCase().startsWith(t.toLowerCase())?e:e.slice(t.length)||"/"}function cd(e,t,n){const r=t.matched.length-1,o=n.matched.length-1;return r>-1&&r===o&&Cn(t.matched[r],n.matched[o])&&fa(t.params,n.params)&&e(t.query)===e(n.query)&&t.hash===n.hash}function Cn(e,t){return(e.aliasOf||e)===(t.aliasOf||t)}function fa(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!1;for(const n in e)if(!ud(e[n],t[n]))return!1;return!0}function ud(e,t){return dt(e)?mi(e,t):dt(t)?mi(t,e):e===t}function mi(e,t){return dt(t)?e.length===t.length&&e.every((n,r)=>n===t[r]):e.length===1&&e[0]===t}function fd(e,t){if(e.startsWith("/"))return e;if(!e)return t;const n=t.split("/"),r=e.split("/"),o=r[r.length-1];(o===".."||o===".")&&r.push("");let s=n.length-1,i,l;for(i=0;i1&&s--;else break;return n.slice(0,s).join("/")+"/"+r.slice(i).join("/")}const xt={path:"/",name:void 0,params:{},query:{},hash:"",fullPath:"/",matched:[],meta:{},redirectedFrom:void 0};var tr;(function(e){e.pop="pop",e.push="push"})(tr||(tr={}));var Wn;(function(e){e.back="back",e.forward="forward",e.unknown=""})(Wn||(Wn={}));function dd(e){if(!e)if(vn){const t=document.querySelector("base");e=t&&t.getAttribute("href")||"/",e=e.replace(/^\w+:\/\/[^\/]+/,"")}else e="/";return e[0]!=="/"&&e[0]!=="#"&&(e="/"+e),ld(e)}const pd=/^[^#]+#/;function hd(e,t){return e.replace(pd,"#")+t}function md(e,t){const n=document.documentElement.getBoundingClientRect(),r=e.getBoundingClientRect();return{behavior:t.behavior,left:r.left-n.left-(t.left||0),top:r.top-n.top-(t.top||0)}}const oo=()=>({left:window.scrollX,top:window.scrollY});function gd(e){let t;if("el"in e){const n=e.el,r=typeof n=="string"&&n.startsWith("#"),o=typeof n=="string"?r?document.getElementById(n.slice(1)):document.querySelector(n):n;if(!o)return;t=md(o,e)}else t=e;"scrollBehavior"in document.documentElement.style?window.scrollTo(t):window.scrollTo(t.left!=null?t.left:window.scrollX,t.top!=null?t.top:window.scrollY)}function gi(e,t){return(history.state?history.state.position-t:-1)+e}const Bo=new Map;function vd(e,t){Bo.set(e,t)}function _d(e){const t=Bo.get(e);return Bo.delete(e),t}let bd=()=>location.protocol+"//"+location.host;function da(e,t){const{pathname:n,search:r,hash:o}=t,s=e.indexOf("#");if(s>-1){let l=o.includes(e.slice(s))?e.slice(s).length:1,a=o.slice(l);return a[0]!=="/"&&(a="/"+a),hi(a,"")}return hi(n,e)+r+o}function yd(e,t,n,r){let o=[],s=[],i=null;const l=({state:p})=>{const m=da(e,location),v=n.value,y=t.value;let C=0;if(p){if(n.value=m,t.value=p,i&&i===v){i=null;return}C=y?p.position-y.position:0}else r(m);o.forEach(T=>{T(n.value,v,{delta:C,type:tr.pop,direction:C?C>0?Wn.forward:Wn.back:Wn.unknown})})};function a(){i=n.value}function f(p){o.push(p);const m=()=>{const v=o.indexOf(p);v>-1&&o.splice(v,1)};return s.push(m),m}function u(){const{history:p}=window;p.state&&p.replaceState(pe({},p.state,{scroll:oo()}),"")}function c(){for(const p of s)p();s=[],window.removeEventListener("popstate",l),window.removeEventListener("beforeunload",u)}return window.addEventListener("popstate",l),window.addEventListener("beforeunload",u,{passive:!0}),{pauseListeners:a,listen:f,destroy:c}}function vi(e,t,n,r=!1,o=!1){return{back:e,current:t,forward:n,replaced:r,position:window.history.length,scroll:o?oo():null}}function Ed(e){const{history:t,location:n}=window,r={value:da(e,n)},o={value:t.state};o.value||s(r.value,{back:null,current:r.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0);function s(a,f,u){const c=e.indexOf("#"),p=c>-1?(n.host&&document.querySelector("base")?e:e.slice(c))+a:bd()+e+a;try{t[u?"replaceState":"pushState"](f,"",p),o.value=f}catch(m){console.error(m),n[u?"replace":"assign"](p)}}function i(a,f){const u=pe({},t.state,vi(o.value.back,a,o.value.forward,!0),f,{position:o.value.position});s(a,u,!0),r.value=a}function l(a,f){const u=pe({},o.value,t.state,{forward:a,scroll:oo()});s(u.current,u,!0);const c=pe({},vi(r.value,a,null),{position:u.position+1},f);s(a,c,!1),r.value=a}return{location:r,state:o,push:l,replace:i}}function wd(e){e=dd(e);const t=Ed(e),n=yd(e,t.state,t.location,t.replace);function r(s,i=!0){i||n.pauseListeners(),history.go(s)}const o=pe({location:"",base:e,go:r,createHref:hd.bind(null,e)},t,n);return Object.defineProperty(o,"location",{enumerable:!0,get:()=>t.location.value}),Object.defineProperty(o,"state",{enumerable:!0,get:()=>t.state.value}),o}function Sd(e){return typeof e=="string"||e&&typeof e=="object"}function pa(e){return typeof e=="string"||typeof e=="symbol"}const ha=Symbol("");var _i;(function(e){e[e.aborted=4]="aborted",e[e.cancelled=8]="cancelled",e[e.duplicated=16]="duplicated"})(_i||(_i={}));function Tn(e,t){return pe(new Error,{type:e,[ha]:!0},t)}function St(e,t){return e instanceof Error&&ha in e&&(t==null||!!(e.type&t))}const bi="[^/]+?",Pd={sensitive:!1,strict:!1,start:!0,end:!0},xd=/[.+*?^${}()[\]/\\]/g;function Ld(e,t){const n=pe({},Pd,t),r=[];let o=n.start?"^":"";const s=[];for(const f of e){const u=f.length?[]:[90];n.strict&&!f.length&&(o+="/");for(let c=0;ct.length?t.length===1&&t[0]===80?1:-1:0}function ma(e,t){let n=0;const r=e.score,o=t.score;for(;n0&&t[t.length-1]<0}const Td={type:0,value:""},kd=/[a-zA-Z0-9_]/;function Ad(e){if(!e)return[[]];if(e==="/")return[[Td]];if(!e.startsWith("/"))throw new Error(`Invalid path "${e}"`);function t(m){throw new Error(`ERR (${n})/"${f}": ${m}`)}let n=0,r=n;const o=[];let s;function i(){s&&o.push(s),s=[]}let l=0,a,f="",u="";function c(){f&&(n===0?s.push({type:0,value:f}):n===1||n===2||n===3?(s.length>1&&(a==="*"||a==="+")&&t(`A repeatable param (${f}) must be alone in its segment. eg: '/:ids+.`),s.push({type:1,value:f,regexp:u,repeatable:a==="*"||a==="+",optional:a==="*"||a==="?"})):t("Invalid state to consume buffer"),f="")}function p(){f+=a}for(;l{i(g)}:Un}function i(c){if(pa(c)){const p=r.get(c);p&&(r.delete(c),n.splice(n.indexOf(p),1),p.children.forEach(i),p.alias.forEach(i))}else{const p=n.indexOf(c);p>-1&&(n.splice(p,1),c.record.name&&r.delete(c.record.name),c.children.forEach(i),c.alias.forEach(i))}}function l(){return n}function a(c){const p=Md(c,n);n.splice(p,0,c),c.record.name&&!Si(c)&&r.set(c.record.name,c)}function f(c,p){let m,v={},y,C;if("name"in c&&c.name){if(m=r.get(c.name),!m)throw Tn(1,{location:c});C=m.record.name,v=pe(Ei(p.params,m.keys.filter(g=>!g.optional).concat(m.parent?m.parent.keys.filter(g=>g.optional):[]).map(g=>g.name)),c.params&&Ei(c.params,m.keys.map(g=>g.name))),y=m.stringify(v)}else if(c.path!=null)y=c.path,m=n.find(g=>g.re.test(y)),m&&(v=m.parse(y),C=m.record.name);else{if(m=p.name?r.get(p.name):n.find(g=>g.re.test(p.path)),!m)throw Tn(1,{location:c,currentLocation:p});C=m.record.name,v=pe({},p.params,c.params),y=m.stringify(v)}const T=[];let S=m;for(;S;)T.unshift(S.record),S=S.parent;return{name:C,path:y,params:v,matched:T,meta:Dd(T)}}e.forEach(c=>s(c));function u(){n.length=0,r.clear()}return{addRoute:s,resolve:f,removeRoute:i,clearRoutes:u,getRoutes:l,getRecordMatcher:o}}function Ei(e,t){const n={};for(const r of t)r in e&&(n[r]=e[r]);return n}function wi(e){const t={path:e.path,redirect:e.redirect,name:e.name,meta:e.meta||{},aliasOf:e.aliasOf,beforeEnter:e.beforeEnter,props:Id(e),children:e.children||[],instances:{},leaveGuards:new Set,updateGuards:new Set,enterCallbacks:{},components:"components"in e?e.components||null:e.component&&{default:e.component}};return Object.defineProperty(t,"mods",{value:{}}),t}function Id(e){const t={},n=e.props||!1;if("component"in e)t.default=n;else for(const r in e.components)t[r]=typeof n=="object"?n[r]:n;return t}function Si(e){for(;e;){if(e.record.aliasOf)return!0;e=e.parent}return!1}function Dd(e){return e.reduce((t,n)=>pe(t,n.meta),{})}function Pi(e,t){const n={};for(const r in e)n[r]=r in t?t[r]:e[r];return n}function Md(e,t){let n=0,r=t.length;for(;n!==r;){const s=n+r>>1;ma(e,t[s])<0?r=s:n=s+1}const o=Vd(e);return o&&(r=t.lastIndexOf(o,r-1)),r}function Vd(e){let t=e;for(;t=t.parent;)if(ga(t)&&ma(e,t)===0)return t}function ga({record:e}){return!!(e.name||e.components&&Object.keys(e.components).length||e.redirect)}function Hd(e){const t={};if(e===""||e==="?")return t;const r=(e[0]==="?"?e.slice(1):e).split("&");for(let o=0;os&&jo(s)):[r&&jo(r)]).forEach(s=>{s!==void 0&&(t+=(t.length?"&":"")+n,s!=null&&(t+="="+s))})}return t}function $d(e){const t={};for(const n in e){const r=e[n];r!==void 0&&(t[n]=dt(r)?r.map(o=>o==null?null:""+o):r==null?r:""+r)}return t}const Nd=Symbol(""),Li=Symbol(""),so=Symbol(""),ms=Symbol(""),Fo=Symbol("");function Hn(){let e=[];function t(r){return e.push(r),()=>{const o=e.indexOf(r);o>-1&&e.splice(o,1)}}function n(){e=[]}return{add:t,list:()=>e.slice(),reset:n}}function Nt(e,t,n,r,o,s=i=>i()){const i=r&&(r.enterCallbacks[o]=r.enterCallbacks[o]||[]);return()=>new Promise((l,a)=>{const f=p=>{p===!1?a(Tn(4,{from:n,to:t})):p instanceof Error?a(p):Sd(p)?a(Tn(2,{from:t,to:p})):(i&&r.enterCallbacks[o]===i&&typeof p=="function"&&i.push(p),l())},u=s(()=>e.call(r&&r.instances[o],t,n,f));let c=Promise.resolve(u);e.length<3&&(c=c.then(f)),c.catch(p=>a(p))})}function Lo(e,t,n,r,o=s=>s()){const s=[];for(const i of e)for(const l in i.components){let a=i.components[l];if(!(t!=="beforeRouteEnter"&&!i.instances[l]))if(sa(a)){const u=(a.__vccOpts||a)[t];u&&s.push(Nt(u,n,r,i,l,o))}else{let f=a();s.push(()=>f.then(u=>{if(!u)throw new Error(`Couldn't resolve component "${l}" at "${i.path}"`);const c=Kf(u)?u.default:u;i.mods[l]=u,i.components[l]=c;const m=(c.__vccOpts||c)[t];return m&&Nt(m,n,r,i,l,o)()}))}}return s}function Ci(e){const t=Fe(so),n=Fe(ms),r=H(()=>{const a=sn(e.to);return t.resolve(a)}),o=H(()=>{const{matched:a}=r.value,{length:f}=a,u=a[f-1],c=n.matched;if(!u||!c.length)return-1;const p=c.findIndex(Cn.bind(null,u));if(p>-1)return p;const m=Ti(a[f-2]);return f>1&&Ti(u)===m&&c[c.length-1].path!==m?c.findIndex(Cn.bind(null,a[f-2])):p}),s=H(()=>o.value>-1&&zd(n.params,r.value.params)),i=H(()=>o.value>-1&&o.value===n.matched.length-1&&fa(n.params,r.value.params));function l(a={}){return Fd(a)?t[sn(e.replace)?"replace":"push"](sn(e.to)).catch(Un):Promise.resolve()}return{route:r,href:H(()=>r.value.href),isActive:s,isExactActive:i,navigate:l}}const jd=fe({name:"RouterLink",compatConfig:{MODE:3},props:{to:{type:[String,Object],required:!0},replace:Boolean,activeClass:String,exactActiveClass:String,custom:Boolean,ariaCurrentValue:{type:String,default:"page"}},useLink:Ci,setup(e,{slots:t}){const n=lr(Ci(e)),{options:r}=Fe(so),o=H(()=>({[ki(e.activeClass,r.linkActiveClass,"router-link-active")]:n.isActive,[ki(e.exactActiveClass,r.linkExactActiveClass,"router-link-exact-active")]:n.isExactActive}));return()=>{const s=t.default&&t.default(n);return e.custom?s:Ve("a",{"aria-current":n.isExactActive?e.ariaCurrentValue:null,href:n.href,onClick:n.navigate,class:o.value},s)}}}),Bd=jd;function Fd(e){if(!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)&&!e.defaultPrevented&&!(e.button!==void 0&&e.button!==0)){if(e.currentTarget&&e.currentTarget.getAttribute){const t=e.currentTarget.getAttribute("target");if(/\b_blank\b/i.test(t))return}return e.preventDefault&&e.preventDefault(),!0}}function zd(e,t){for(const n in t){const r=t[n],o=e[n];if(typeof r=="string"){if(r!==o)return!1}else if(!dt(o)||o.length!==r.length||r.some((s,i)=>s!==o[i]))return!1}return!0}function Ti(e){return e?e.aliasOf?e.aliasOf.path:e.path:""}const ki=(e,t,n)=>e??t??n,Ud=fe({name:"RouterView",inheritAttrs:!1,props:{name:{type:String,default:"default"},route:Object},compatConfig:{MODE:3},setup(e,{attrs:t,slots:n}){const r=Fe(Fo),o=H(()=>e.route||r.value),s=Fe(Li,0),i=H(()=>{let f=sn(s);const{matched:u}=o.value;let c;for(;(c=u[f])&&!c.components;)f++;return f}),l=H(()=>o.value.matched[i.value]);an(Li,H(()=>i.value+1)),an(Nd,l),an(Fo,o);const a=ge();return ze(()=>[a.value,l.value,e.name],([f,u,c],[p,m,v])=>{u&&(u.instances[c]=f,m&&m!==u&&f&&f===p&&(u.leaveGuards.size||(u.leaveGuards=m.leaveGuards),u.updateGuards.size||(u.updateGuards=m.updateGuards))),f&&u&&(!m||!Cn(u,m)||!p)&&(u.enterCallbacks[c]||[]).forEach(y=>y(f))},{flush:"post"}),()=>{const f=o.value,u=e.name,c=l.value,p=c&&c.components[u];if(!p)return Ai(n.default,{Component:p,route:f});const m=c.props[u],v=m?m===!0?f.params:typeof m=="function"?m(f):m:null,C=Ve(p,pe({},v,t,{onVnodeUnmounted:T=>{T.component.isUnmounted&&(c.instances[u]=null)},ref:a}));return Ai(n.default,{Component:C,route:f})||C}}});function Ai(e,t){if(!e)return null;const n=e(t);return n.length===1?n[0]:n}const Wd=Ud;function Kd(e){const t=Rd(e.routes,e),n=e.parseQuery||Hd,r=e.stringifyQuery||xi,o=e.history,s=Hn(),i=Hn(),l=Hn(),a=fn(xt);let f=xt;vn&&e.scrollBehavior&&"scrollRestoration"in history&&(history.scrollRestoration="manual");const u=Po.bind(null,L=>""+L),c=Po.bind(null,sd),p=Po.bind(null,er);function m(L,U){let B,Y;return pa(L)?(B=t.getRecordMatcher(L),Y=U):Y=L,t.addRoute(Y,B)}function v(L){const U=t.getRecordMatcher(L);U&&t.removeRoute(U)}function y(){return t.getRoutes().map(L=>L.record)}function C(L){return!!t.getRecordMatcher(L)}function T(L,U){if(U=pe({},U||a.value),typeof L=="string"){const h=xo(n,L,U.path),_=t.resolve({path:h.path},U),k=o.createHref(h.fullPath);return pe(h,_,{params:p(_.params),hash:er(h.hash),redirectedFrom:void 0,href:k})}let B;if(L.path!=null)B=pe({},L,{path:xo(n,L.path,U.path).path});else{const h=pe({},L.params);for(const _ in h)h[_]==null&&delete h[_];B=pe({},L,{params:c(h)}),U.params=c(U.params)}const Y=t.resolve(B,U),le=L.hash||"";Y.params=u(p(Y.params));const he=ad(r,pe({},L,{hash:nd(le),path:Y.path})),d=o.createHref(he);return pe({fullPath:he,hash:le,query:r===xi?$d(L.query):L.query||{}},Y,{redirectedFrom:void 0,href:d})}function S(L){return typeof L=="string"?xo(n,L,a.value.path):pe({},L)}function g(L,U){if(f!==L)return Tn(8,{from:U,to:L})}function b(L){return D(L)}function V(L){return b(pe(S(L),{replace:!0}))}function q(L){const U=L.matched[L.matched.length-1];if(U&&U.redirect){const{redirect:B}=U;let Y=typeof B=="function"?B(L):B;return typeof Y=="string"&&(Y=Y.includes("?")||Y.includes("#")?Y=S(Y):{path:Y},Y.params={}),pe({query:L.query,hash:L.hash,params:Y.path!=null?{}:L.params},Y)}}function D(L,U){const B=f=T(L),Y=a.value,le=L.state,he=L.force,d=L.replace===!0,h=q(B);if(h)return D(pe(S(h),{state:typeof h=="object"?pe({},le,h.state):le,force:he,replace:d}),U||B);const _=B;_.redirectedFrom=U;let k;return!he&&cd(r,Y,B)&&(k=Tn(16,{to:_,from:Y}),Ye(Y,Y,!0,!1)),(k?Promise.resolve(k):x(_,Y)).catch(P=>St(P)?St(P,2)?P:He(P):W(P,_,Y)).then(P=>{if(P){if(St(P,2))return D(pe({replace:d},S(P.to),{state:typeof P.to=="object"?pe({},le,P.to.state):le,force:he}),U||_)}else P=E(_,Y,!0,d,le);return j(_,Y,P),P})}function w(L,U){const B=g(L,U);return B?Promise.reject(B):Promise.resolve()}function z(L){const U=Rt.values().next().value;return U&&typeof U.runWithContext=="function"?U.runWithContext(L):L()}function x(L,U){let B;const[Y,le,he]=Gd(L,U);B=Lo(Y.reverse(),"beforeRouteLeave",L,U);for(const h of Y)h.leaveGuards.forEach(_=>{B.push(Nt(_,L,U))});const d=w.bind(null,L,U);return B.push(d),Je(B).then(()=>{B=[];for(const h of s.list())B.push(Nt(h,L,U));return B.push(d),Je(B)}).then(()=>{B=Lo(le,"beforeRouteUpdate",L,U);for(const h of le)h.updateGuards.forEach(_=>{B.push(Nt(_,L,U))});return B.push(d),Je(B)}).then(()=>{B=[];for(const h of he)if(h.beforeEnter)if(dt(h.beforeEnter))for(const _ of h.beforeEnter)B.push(Nt(_,L,U));else B.push(Nt(h.beforeEnter,L,U));return B.push(d),Je(B)}).then(()=>(L.matched.forEach(h=>h.enterCallbacks={}),B=Lo(he,"beforeRouteEnter",L,U,z),B.push(d),Je(B))).then(()=>{B=[];for(const h of i.list())B.push(Nt(h,L,U));return B.push(d),Je(B)}).catch(h=>St(h,8)?h:Promise.reject(h))}function j(L,U,B){l.list().forEach(Y=>z(()=>Y(L,U,B)))}function E(L,U,B,Y,le){const he=g(L,U);if(he)return he;const d=U===xt,h=vn?history.state:{};B&&(Y||d?o.replace(L.fullPath,pe({scroll:d&&h&&h.scroll},le)):o.push(L.fullPath,le)),a.value=L,Ye(L,U,B,d),He()}let M;function X(){M||(M=o.listen((L,U,B)=>{if(!pt.listening)return;const Y=T(L),le=q(Y);if(le){D(pe(le,{replace:!0}),Y).catch(Un);return}f=Y;const he=a.value;vn&&vd(gi(he.fullPath,B.delta),oo()),x(Y,he).catch(d=>St(d,12)?d:St(d,2)?(D(d.to,Y).then(h=>{St(h,20)&&!B.delta&&B.type===tr.pop&&o.go(-1,!1)}).catch(Un),Promise.reject()):(B.delta&&o.go(-B.delta,!1),W(d,Y,he))).then(d=>{d=d||E(Y,he,!1),d&&(B.delta&&!St(d,8)?o.go(-B.delta,!1):B.type===tr.pop&&St(d,20)&&o.go(-1,!1)),j(Y,he,d)}).catch(Un)}))}let ie=Hn(),I=Hn(),J;function W(L,U,B){He(L);const Y=I.list();return Y.length?Y.forEach(le=>le(L,U,B)):console.error(L),Promise.reject(L)}function be(){return J&&a.value!==xt?Promise.resolve():new Promise((L,U)=>{ie.add([L,U])})}function He(L){return J||(J=!L,X(),ie.list().forEach(([U,B])=>L?B(L):U()),ie.reset()),L}function Ye(L,U,B,Y){const{scrollBehavior:le}=e;if(!vn||!le)return Promise.resolve();const he=!B&&_d(gi(L.fullPath,0))||(Y||!B)&&history.state&&history.state.scroll||null;return An().then(()=>le(L,U,he)).then(d=>d&&gd(d)).catch(d=>W(d,L,U))}const $e=L=>o.go(L);let Ot;const Rt=new Set,pt={currentRoute:a,listening:!0,addRoute:m,removeRoute:v,clearRoutes:t.clearRoutes,hasRoute:C,getRoutes:y,resolve:T,options:e,push:b,replace:V,go:$e,back:()=>$e(-1),forward:()=>$e(1),beforeEach:s.add,beforeResolve:i.add,afterEach:l.add,onError:I.add,isReady:be,install(L){const U=this;L.component("RouterLink",Bd),L.component("RouterView",Wd),L.config.globalProperties.$router=U,Object.defineProperty(L.config.globalProperties,"$route",{enumerable:!0,get:()=>sn(a)}),vn&&!Ot&&a.value===xt&&(Ot=!0,b(o.location).catch(le=>{}));const B={};for(const le in xt)Object.defineProperty(B,le,{get:()=>a.value[le],enumerable:!0});L.provide(so,U),L.provide(ms,fl(B)),L.provide(Fo,a);const Y=L.unmount;Rt.add(L),L.unmount=function(){Rt.delete(L),Rt.size<1&&(f=xt,M&&M(),M=null,a.value=xt,Ot=!1,J=!1),Y()}}};function Je(L){return L.reduce((U,B)=>U.then(()=>z(B)),Promise.resolve())}return pt}function Gd(e,t){const n=[],r=[],o=[],s=Math.max(t.matched.length,e.matched.length);for(let i=0;iCn(f,l))?r.push(l):n.push(l));const a=e.matched[i];a&&(t.matched.find(f=>Cn(f,a))||o.push(a))}return[n,r,o]}function qt(){return Fe(so)}function At(e){return Fe(ms)}var gs=Symbol(""),yt=()=>{const e=Fe(gs);if(!e)throw new Error("useClientData() is called without provider.");return e},qd=()=>yt().pageComponent,On=()=>yt().pageData,Et=()=>yt().pageFrontmatter,Yd=()=>yt().pageHead,va=()=>yt().pageLang,Jd=()=>yt().pageLayout,dn=()=>yt().routeLocale,Qd=()=>yt().routes,_a=()=>yt().siteData,vs=()=>yt().siteLocaleData,Xd=Symbol(""),zo=fn(Uf),xn=fn(Wf),ba=(e,t)=>{const n=If(e,t);if(xn.value[n])return n;const r=encodeURI(n);if(xn.value[r])return r;const o=zo.value[n]||zo.value[r];return o||n},nr=(e,t)=>{const{pathname:n,hashAndQueries:r}=ra(e),o=ba(n,t),s=o+r;return xn.value[o]?{...xn.value[o],path:s,notFound:!1}:{...xn.value["/404.html"],path:s,notFound:!0}},Zd=(e,t)=>{const{pathname:n,hashAndQueries:r}=ra(e);return ba(n,t)+r},ep=e=>{if(!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)&&!e.defaultPrevented&&!(e.button!==void 0&&e.button!==0)){if(e.currentTarget){const t=e.currentTarget.getAttribute("target");if(t!=null&&t.match(/\b_blank\b/i))return}return e.preventDefault(),!0}},io=fe({name:"RouteLink",props:{to:{type:String,required:!0},active:Boolean,activeClass:{type:String,default:"route-link-active"}},slots:Object,setup(e,{slots:t}){const n=qt(),r=At(),o=H(()=>e.to.startsWith("#")||e.to.startsWith("?")?e.to:`/docs/${Zd(e.to,r.path).substring(1)}`);return()=>{var s;return Ve("a",{class:["route-link",{[e.activeClass]:e.active}],href:o.value,onClick:(i={})=>{ep(i)&&n.push(e.to).catch()}},(s=t.default)==null?void 0:s.call(t))}}}),Rn=fe({name:"AutoLink",props:{config:{type:Object,required:!0}},slots:Object,setup(e,{slots:t}){const n=Dc(e,"config"),r=At(),o=_a(),s=H(()=>mr(n.value.link)),i=H(()=>n.value.target||(s.value?"_blank":void 0)),l=H(()=>i.value==="_blank"),a=H(()=>!s.value&&!l.value),f=H(()=>n.value.rel||(l.value?"noopener noreferrer":null)),u=H(()=>n.value.ariaLabel??n.value.text),c=H(()=>{if(n.value.exact)return!1;const m=Object.keys(o.value.locales);return m.length?m.every(v=>v!==n.value.link):n.value.link!=="/"}),p=H(()=>a.value?n.value.activeMatch?(n.value.activeMatch instanceof RegExp?n.value.activeMatch:new RegExp(n.value.activeMatch,"u")).test(r.path):c.value?r.path.startsWith(n.value.link):r.path===n.value.link:!1);return()=>{const{before:m,after:v,default:y}=t,C=(y==null?void 0:y(n.value))||[m==null?void 0:m(n.value),n.value.text,v==null?void 0:v(n.value)];return a.value?Ve(io,{class:"auto-link",to:n.value.link,active:p.value,"aria-label":u.value},()=>C):Ve("a",{class:"auto-link external-link",href:n.value.link,"aria-label":u.value,rel:f.value,target:i.value},C)}}}),_s=fe({name:"ClientOnly",setup(e,t){const n=ge(!1);return We(()=>{n.value=!0}),()=>{var r,o;return n.value?(o=(r=t.slots).default)==null?void 0:o.call(r):null}}}),bs=fe({name:"Content",props:{path:{type:String,required:!1,default:""}},setup(e){const t=qd(),n=H(()=>{if(!e.path)return t.value;const r=nr(e.path);return Se(()=>r.loader().then(({comp:o})=>o))});return()=>Ve(n.value)}}),tp="Layout",np="en-US",Zt=lr({resolveLayouts:e=>e.reduce((t,n)=>({...t,...n.layouts}),{}),resolvePageHead:(e,t,n)=>{const r=ut(t.description)?t.description:n.description,o=[...Array.isArray(t.head)?t.head:[],...n.head,["title",{},e],["meta",{name:"description",content:r}]];return jf(o)},resolvePageHeadTitle:(e,t)=>[e.title,t.title].filter(n=>!!n).join(" | "),resolvePageLang:(e,t)=>e.lang||t.lang||np,resolvePageLayout:(e,t)=>{const n=ut(e.frontmatter.layout)?e.frontmatter.layout:tp;if(!t[n])throw new Error(`[vuepress] Cannot resolve layout: ${n}`);return t[n]},resolveRouteLocale:(e,t)=>Df(e,decodeURI(t)),resolveSiteLocaleData:({base:e,locales:t,...n},r)=>{var o;return{...n,...t[r],head:[...((o=t[r])==null?void 0:o.head)??[],...n.head??[]]}}}),Yt=(e={})=>e,ys=e=>ro(e)?e:`/docs/${ds(e)}`;function Es(e){return Ji()?(oc(e),!0):!1}function _t(e){return typeof e=="function"?e():sn(e)}const ws=typeof window<"u"&&typeof document<"u";typeof WorkerGlobalScope<"u"&&globalThis instanceof WorkerGlobalScope;const rp=Object.prototype.toString,op=e=>rp.call(e)==="[object Object]",Uo=()=>{};function ya(e,t){function n(...r){return new Promise((o,s)=>{Promise.resolve(e(()=>t.apply(this,r),{fn:t,thisArg:this,args:r})).then(o).catch(s)})}return n}const Ea=e=>e();function sp(e,t={}){let n,r,o=Uo;const s=l=>{clearTimeout(l),o(),o=Uo};return l=>{const a=_t(e),f=_t(t.maxWait);return n&&s(n),a<=0||f!==void 0&&f<=0?(r&&(s(r),r=null),Promise.resolve(l())):new Promise((u,c)=>{o=t.rejectOnCancel?c:u,f&&!r&&(r=setTimeout(()=>{n&&s(n),r=null,u(l())},f)),n=setTimeout(()=>{r&&s(r),r=null,u(l())},a)})}}function ip(e=Ea){const t=ge(!0);function n(){t.value=!1}function r(){t.value=!0}const o=(...s)=>{t.value&&e(...s)};return{isActive:Xr(t),pause:n,resume:r,eventFilter:o}}function lp(e){let t;function n(){return t||(t=e()),t}return n.reset=async()=>{const r=t;t=void 0,r&&await r},n}function ap(e){return dr()}function cp(e,t=200,n={}){return ya(sp(t,n),e)}function up(e,t,n={}){const{eventFilter:r=Ea,...o}=n;return ze(e,ya(r,t),o)}function fp(e,t,n={}){const{eventFilter:r,...o}=n,{eventFilter:s,pause:i,resume:l,isActive:a}=ip(r);return{stop:up(e,t,{...o,eventFilter:s}),pause:i,resume:l,isActive:a}}function dp(e,t=!0,n){ap()?We(e,n):t?e():An(e)}function pp(e,t,n={}){const{immediate:r=!0}=n,o=ge(!1);let s=null;function i(){s&&(clearTimeout(s),s=null)}function l(){o.value=!1,i()}function a(...f){i(),o.value=!0,s=setTimeout(()=>{o.value=!1,s=null,e(...f)},_t(t))}return r&&(o.value=!0,ws&&a()),Es(l),{isPending:Xr(o),start:a,stop:l}}function hp(e=!1,t={}){const{truthyValue:n=!0,falsyValue:r=!1}=t,o=Oe(e),s=ge(e);function i(l){if(arguments.length)return s.value=l,s.value;{const a=_t(n);return s.value=s.value===a?_t(r):a,s.value}}return o?i:[s,i]}const Kr=ws?window:void 0,wa=ws?window.navigator:void 0;function mp(e){var t;const n=_t(e);return(t=n==null?void 0:n.$el)!=null?t:n}function bt(...e){let t,n,r,o;if(typeof e[0]=="string"||Array.isArray(e[0])?([n,r,o]=e,t=Kr):[t,n,r,o]=e,!t)return Uo;Array.isArray(n)||(n=[n]),Array.isArray(r)||(r=[r]);const s=[],i=()=>{s.forEach(u=>u()),s.length=0},l=(u,c,p,m)=>(u.addEventListener(c,p,m),()=>u.removeEventListener(c,p,m)),a=ze(()=>[mp(t),_t(o)],([u,c])=>{if(i(),!u)return;const p=op(c)?{...c}:c;s.push(...n.flatMap(m=>r.map(v=>l(u,m,v,p))))},{immediate:!0,flush:"post"}),f=()=>{a(),i()};return Es(f),f}function gp(){const e=ge(!1),t=dr();return t&&We(()=>{e.value=!0},t),e}function Ss(e){const t=gp();return H(()=>(t.value,!!e()))}function Sa(e,t={}){const{window:n=Kr}=t,r=Ss(()=>n&&"matchMedia"in n&&typeof n.matchMedia=="function");let o;const s=ge(!1),i=f=>{s.value=f.matches},l=()=>{o&&("removeEventListener"in o?o.removeEventListener("change",i):o.removeListener(i))},a=Cu(()=>{r.value&&(l(),o=n.matchMedia(_t(e)),"addEventListener"in o?o.addEventListener("change",i):o.addListener(i),s.value=o.matches)});return Es(()=>{a(),l(),o=void 0}),s}function Oi(e,t={}){const{controls:n=!1,navigator:r=wa}=t,o=Ss(()=>r&&"permissions"in r),s=fn(),i=typeof e=="string"?{name:e}:e,l=fn(),a=()=>{var u,c;l.value=(c=(u=s.value)==null?void 0:u.state)!=null?c:"prompt"};bt(s,"change",a);const f=lp(async()=>{if(o.value){if(!s.value)try{s.value=await r.permissions.query(i)}catch{s.value=void 0}finally{a()}if(n)return ce(s.value)}});return f(),n?{state:l,isSupported:o,query:f}:l}function vp(e={}){const{navigator:t=wa,read:n=!1,source:r,copiedDuring:o=1500,legacy:s=!1}=e,i=Ss(()=>t&&"clipboard"in t),l=Oi("clipboard-read"),a=Oi("clipboard-write"),f=H(()=>i.value||s),u=ge(""),c=ge(!1),p=pp(()=>c.value=!1,o);function m(){i.value&&T(l.value)?t.clipboard.readText().then(S=>{u.value=S}):u.value=C()}f.value&&n&&bt(["copy","cut"],m);async function v(S=_t(r)){f.value&&S!=null&&(i.value&&T(a.value)?await t.clipboard.writeText(S):y(S),u.value=S,c.value=!0,p.start())}function y(S){const g=document.createElement("textarea");g.value=S??"",g.style.position="absolute",g.style.opacity="0",document.body.appendChild(g),g.select(),document.execCommand("copy"),g.remove()}function C(){var S,g,b;return(b=(g=(S=document==null?void 0:document.getSelection)==null?void 0:S.call(document))==null?void 0:g.toString())!=null?b:""}function T(S){return S==="granted"||S==="prompt"}return{isSupported:f,text:u,copied:c,copy:v}}const xr=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{},Lr="__vueuse_ssr_handlers__",_p=bp();function bp(){return Lr in xr||(xr[Lr]=xr[Lr]||{}),xr[Lr]}function yp(e,t){return _p[e]||t}function Ep(e){return Sa("(prefers-color-scheme: dark)",e)}function wp(e){return e==null?"any":e instanceof Set?"set":e instanceof Map?"map":e instanceof Date?"date":typeof e=="boolean"?"boolean":typeof e=="string"?"string":typeof e=="object"?"object":Number.isNaN(e)?"any":"number"}const Sp={boolean:{read:e=>e==="true",write:e=>String(e)},object:{read:e=>JSON.parse(e),write:e=>JSON.stringify(e)},number:{read:e=>Number.parseFloat(e),write:e=>String(e)},any:{read:e=>e,write:e=>String(e)},string:{read:e=>e,write:e=>String(e)},map:{read:e=>new Map(JSON.parse(e)),write:e=>JSON.stringify(Array.from(e.entries()))},set:{read:e=>new Set(JSON.parse(e)),write:e=>JSON.stringify(Array.from(e))},date:{read:e=>new Date(e),write:e=>e.toISOString()}},Ri="vueuse-storage";function Pa(e,t,n,r={}){var o;const{flush:s="pre",deep:i=!0,listenToStorageChanges:l=!0,writeDefaults:a=!0,mergeDefaults:f=!1,shallow:u,window:c=Kr,eventFilter:p,onError:m=x=>{console.error(x)},initOnMounted:v}=r,y=(u?fn:ge)(typeof t=="function"?t():t);if(!n)try{n=yp("getDefaultStorage",()=>{var x;return(x=Kr)==null?void 0:x.localStorage})()}catch(x){m(x)}if(!n)return y;const C=_t(t),T=wp(C),S=(o=r.serializer)!=null?o:Sp[T],{pause:g,resume:b}=fp(y,()=>q(y.value),{flush:s,deep:i,eventFilter:p});c&&l&&dp(()=>{n instanceof Storage?bt(c,"storage",w):bt(c,Ri,z),v&&w()}),v||w();function V(x,j){if(c){const E={key:e,oldValue:x,newValue:j,storageArea:n};c.dispatchEvent(n instanceof Storage?new StorageEvent("storage",E):new CustomEvent(Ri,{detail:E}))}}function q(x){try{const j=n.getItem(e);if(x==null)V(j,null),n.removeItem(e);else{const E=S.write(x);j!==E&&(n.setItem(e,E),V(j,E))}}catch(j){m(j)}}function D(x){const j=x?x.newValue:n.getItem(e);if(j==null)return a&&C!=null&&n.setItem(e,S.write(C)),C;if(!x&&f){const E=S.read(j);return typeof f=="function"?f(E,C):T==="object"&&!Array.isArray(E)?{...C,...E}:E}else return typeof j!="string"?j:S.read(j)}function w(x){if(!(x&&x.storageArea!==n)){if(x&&x.key==null){y.value=C;return}if(!(x&&x.key!==e)){g();try{(x==null?void 0:x.newValue)!==S.write(y.value)&&(y.value=D(x))}catch(j){m(j)}finally{x?An(b):b()}}}}function z(x){w(x.detail)}return y}const Ii=async(e,t)=>{const{path:n,query:r}=e.currentRoute.value,{scrollBehavior:o}=e.options;e.options.scrollBehavior=void 0,await e.replace({path:n,query:r,hash:t}),e.options.scrollBehavior=o},Pp=({headerLinkSelector:e,headerAnchorSelector:t,delay:n,offset:r=5})=>{const o=qt();bt("scroll",cp(()=>{var v,y;const i=Math.max(window.scrollY,document.documentElement.scrollTop,document.body.scrollTop);if(Math.abs(i-0)c.some(T=>T.hash===C.hash));for(let C=0;C=(((v=T.parentElement)==null?void 0:v.offsetTop)??0)-r,b=!S||i<(((y=S.parentElement)==null?void 0:y.offsetTop)??0)-r;if(!(g&&b))continue;const q=decodeURIComponent(o.currentRoute.value.hash),D=decodeURIComponent(T.hash);if(q===D)return;if(u){for(let w=C+1;w{const t=dn();return H(()=>e[t.value]??{})},Rp=()=>{const e=Qd();return H(()=>Object.keys(e.value))},Rr=(e,t)=>{var r;const n=(r=dr())==null?void 0:r.appContext.components;return n?e in n||rt(e)in n||sr(rt(e))in n:!1},xa=e=>new Promise(t=>{setTimeout(t,e)}),Ip=(e,t=2)=>{if(t===!1)return[];const[n,r]=typeof t=="number"?[t,t]:t==="deep"?[2,6]:t,o=e.filter(i=>i.level>=n&&i.level<=r),s=[];e:for(let i=0;i=0;a--){const f=o[a];if(f.level{let n;if(t.length){const r=e.cloneNode(!0);r.querySelectorAll(t.join(",")).forEach(o=>{o.remove()}),n=r.textContent||""}else n=e.textContent||"";return n.trim()},Mp=({selector:e=[...new Array(6)].map((r,o)=>`[vp-content] h${o+1}`).join(","),levels:t=2,ignore:n=[]}={})=>{const r=Array.from(document.querySelectorAll(e)).filter(o=>o.id&&o.hasChildNodes()).map(o=>{const s=Number(o.tagName[1]);return{element:o,title:Dp(o,n),link:`#${o.id}`,slug:o.id,level:s}});return Ip(r,t)},Vp=e=>typeof e<"u",La=(e,t)=>ut(e)&&e.startsWith(t),{keys:Hp}=Object,Ca=e=>La(e,"/"),$p=/language-(shellscript|shell|bash|sh|zsh)/,Np=({delay:e=500,duration:t=2e3,locales:n,selector:r,showInMobile:o,ignoreSelector:s=[],transform:i})=>{const l=Sa("(max-width: 419px)"),a=H(()=>!l.value||o),f=Op(n),u=On(),c=C=>{var S;if(C.hasAttribute("copy-code"))return;const T=document.createElement("button");T.type="button",T.classList.add("vp-copy-code-button"),T.setAttribute("aria-label",f.value.copy),T.setAttribute("data-copied",f.value.copied),(S=C.parentElement)==null||S.insertBefore(T,C),C.setAttribute("copy-code","")};ze(()=>[u.value.path,a.value],async()=>{document.body.classList.toggle("no-copy-code",!a.value),a.value&&(await An(),await xa(e),document.querySelectorAll(r.join(",")).forEach(c))},{immediate:!0});const{copy:m}=vp({legacy:!0}),v=new WeakMap,y=async(C,T,S)=>{const g=T.cloneNode(!0);s.length&&g.querySelectorAll(s.join(",")).forEach(q=>{q.remove()}),i&&i(g);let b=g.textContent||"";if($p.test(C.className)&&(b=b.replace(/^ *(\$|>) /gm,"")),await m(b),t<=0)return;S.classList.add("copied"),clearTimeout(v.get(S));const V=setTimeout(()=>{S.classList.remove("copied"),S.blur(),v.delete(S)},t);v.set(S,V)};bt("click",C=>{const T=C.target;if(a.value&&T.matches('div[class*="language-"] > button.vp-copy-code-button')){const S=T.parentElement,g=T.nextElementSibling;if(!S||!g)return;y(S,g,T)}})};var jp=[],Bp={"/":{copy:"Copy code",copied:"Copied"}},Fp=['[vp-content] div[class*="language-"] pre'];const zp=Yt({setup:()=>{Np({selector:Fp,ignoreSelector:jp,locales:Bp,duration:2e3,delay:500,showInMobile:!1})}}),Up=Object.freeze(Object.defineProperty({__proto__:null,default:zp},Symbol.toStringTag,{value:"Module"})),Wp=Object.freeze(Object.defineProperty({__proto__:null},Symbol.toStringTag,{value:"Module"}));/*! medium-zoom 1.1.0 | MIT License | https://github.com/francoischalifour/medium-zoom */var tn=Object.assign||function(e){for(var t=1;t1&&arguments[1]!==void 0?arguments[1]:{},r=window.Promise||function(E){function M(){}E(M,M)},o=function(E){var M=E.target;if(M===z){v();return}g.indexOf(M)!==-1&&y({target:M})},s=function(){if(!(V||!w.original)){var E=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0;Math.abs(q-E)>D.scrollOffset&&setTimeout(v,150)}},i=function(E){var M=E.key||E.keyCode;(M==="Escape"||M==="Esc"||M===27)&&v()},l=function(){var E=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},M=E;if(E.background&&(z.style.background=E.background),E.container&&E.container instanceof Object&&(M.container=tn({},D.container,E.container)),E.template){var X=Ir(E.template)?E.template:document.querySelector(E.template);M.template=X}return D=tn({},D,M),g.forEach(function(ie){ie.dispatchEvent(mn("medium-zoom:update",{detail:{zoom:x}}))}),x},a=function(){var E=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};return e(tn({},D,E))},f=function(){for(var E=arguments.length,M=Array(E),X=0;X0?M.reduce(function(I,J){return[].concat(I,Mi(J))},[]):g;return ie.forEach(function(I){I.classList.remove("medium-zoom-image"),I.dispatchEvent(mn("medium-zoom:detach",{detail:{zoom:x}}))}),g=g.filter(function(I){return ie.indexOf(I)===-1}),x},c=function(E,M){var X=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};return g.forEach(function(ie){ie.addEventListener("medium-zoom:"+E,M,X)}),b.push({type:"medium-zoom:"+E,listener:M,options:X}),x},p=function(E,M){var X=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};return g.forEach(function(ie){ie.removeEventListener("medium-zoom:"+E,M,X)}),b=b.filter(function(ie){return!(ie.type==="medium-zoom:"+E&&ie.listener.toString()===M.toString())}),x},m=function(){var E=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},M=E.target,X=function(){var I={width:document.documentElement.clientWidth,height:document.documentElement.clientHeight,left:0,top:0,right:0,bottom:0},J=void 0,W=void 0;if(D.container)if(D.container instanceof Object)I=tn({},I,D.container),J=I.width-I.left-I.right-D.margin*2,W=I.height-I.top-I.bottom-D.margin*2;else{var be=Ir(D.container)?D.container:document.querySelector(D.container),He=be.getBoundingClientRect(),Ye=He.width,$e=He.height,Ot=He.left,Rt=He.top;I=tn({},I,{width:Ye,height:$e,left:Ot,top:Rt})}J=J||I.width-D.margin*2,W=W||I.height-D.margin*2;var pt=w.zoomedHd||w.original,Je=Di(pt)?J:pt.naturalWidth||J,L=Di(pt)?W:pt.naturalHeight||W,U=pt.getBoundingClientRect(),B=U.top,Y=U.left,le=U.width,he=U.height,d=Math.min(Math.max(le,Je),J)/le,h=Math.min(Math.max(he,L),W)/he,_=Math.min(d,h),k=(-Y+(J-le)/2+D.margin+I.left)/_,P=(-B+(W-he)/2+D.margin+I.top)/_,A="scale("+_+") translate3d("+k+"px, "+P+"px, 0)";w.zoomed.style.transform=A,w.zoomedHd&&(w.zoomedHd.style.transform=A)};return new r(function(ie){if(M&&g.indexOf(M)===-1){ie(x);return}var I=function Ye(){V=!1,w.zoomed.removeEventListener("transitionend",Ye),w.original.dispatchEvent(mn("medium-zoom:opened",{detail:{zoom:x}})),ie(x)};if(w.zoomed){ie(x);return}if(M)w.original=M;else if(g.length>0){var J=g;w.original=J[0]}else{ie(x);return}if(w.original.dispatchEvent(mn("medium-zoom:open",{detail:{zoom:x}})),q=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,V=!0,w.zoomed=qp(w.original),document.body.appendChild(z),D.template){var W=Ir(D.template)?D.template:document.querySelector(D.template);w.template=document.createElement("div"),w.template.appendChild(W.content.cloneNode(!0)),document.body.appendChild(w.template)}if(w.original.parentElement&&w.original.parentElement.tagName==="PICTURE"&&w.original.currentSrc&&(w.zoomed.src=w.original.currentSrc),document.body.appendChild(w.zoomed),window.requestAnimationFrame(function(){document.body.classList.add("medium-zoom--opened")}),w.original.classList.add("medium-zoom-image--hidden"),w.zoomed.classList.add("medium-zoom-image--opened"),w.zoomed.addEventListener("click",v),w.zoomed.addEventListener("transitionend",I),w.original.getAttribute("data-zoom-src")){w.zoomedHd=w.zoomed.cloneNode(),w.zoomedHd.removeAttribute("srcset"),w.zoomedHd.removeAttribute("sizes"),w.zoomedHd.removeAttribute("loading"),w.zoomedHd.src=w.zoomed.getAttribute("data-zoom-src"),w.zoomedHd.onerror=function(){clearInterval(be),console.warn("Unable to reach the zoom image target "+w.zoomedHd.src),w.zoomedHd=null,X()};var be=setInterval(function(){w.zoomedHd.complete&&(clearInterval(be),w.zoomedHd.classList.add("medium-zoom-image--opened"),w.zoomedHd.addEventListener("click",v),document.body.appendChild(w.zoomedHd),X())},10)}else if(w.original.hasAttribute("srcset")){w.zoomedHd=w.zoomed.cloneNode(),w.zoomedHd.removeAttribute("sizes"),w.zoomedHd.removeAttribute("loading");var He=w.zoomedHd.addEventListener("load",function(){w.zoomedHd.removeEventListener("load",He),w.zoomedHd.classList.add("medium-zoom-image--opened"),w.zoomedHd.addEventListener("click",v),document.body.appendChild(w.zoomedHd),X()})}else X()})},v=function(){return new r(function(E){if(V||!w.original){E(x);return}var M=function X(){w.original.classList.remove("medium-zoom-image--hidden"),document.body.removeChild(w.zoomed),w.zoomedHd&&document.body.removeChild(w.zoomedHd),document.body.removeChild(z),w.zoomed.classList.remove("medium-zoom-image--opened"),w.template&&document.body.removeChild(w.template),V=!1,w.zoomed.removeEventListener("transitionend",X),w.original.dispatchEvent(mn("medium-zoom:closed",{detail:{zoom:x}})),w.original=null,w.zoomed=null,w.zoomedHd=null,w.template=null,E(x)};V=!0,document.body.classList.remove("medium-zoom--opened"),w.zoomed.style.transform="",w.zoomedHd&&(w.zoomedHd.style.transform=""),w.template&&(w.template.style.transition="opacity 150ms",w.template.style.opacity=0),w.original.dispatchEvent(mn("medium-zoom:close",{detail:{zoom:x}})),w.zoomed.addEventListener("transitionend",M)})},y=function(){var E=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},M=E.target;return w.original?v():m({target:M})},C=function(){return D},T=function(){return g},S=function(){return w.original},g=[],b=[],V=!1,q=0,D=n,w={original:null,zoomed:null,zoomedHd:null,template:null};Object.prototype.toString.call(t)==="[object Object]"?D=t:(t||typeof t=="string")&&f(t),D=tn({margin:0,background:"#fff",scrollOffset:40,container:null,template:null},D);var z=Gp(D.background);document.addEventListener("click",o),document.addEventListener("keyup",i),document.addEventListener("scroll",s),window.addEventListener("resize",v);var x={open:m,close:v,toggle:y,update:l,clone:a,attach:f,detach:u,on:c,off:p,getOptions:C,getImages:T,getZoomedImage:S};return x};function Jp(e,t){t===void 0&&(t={});var n=t.insertAt;if(!(typeof document>"u")){var r=document.head||document.getElementsByTagName("head")[0],o=document.createElement("style");o.type="text/css",n==="top"&&r.firstChild?r.insertBefore(o,r.firstChild):r.appendChild(o),o.styleSheet?o.styleSheet.cssText=e:o.appendChild(document.createTextNode(e))}}var Qp=".medium-zoom-overlay{position:fixed;top:0;right:0;bottom:0;left:0;opacity:0;transition:opacity .3s;will-change:opacity}.medium-zoom--opened .medium-zoom-overlay{cursor:pointer;cursor:zoom-out;opacity:1}.medium-zoom-image{cursor:pointer;cursor:zoom-in;transition:transform .3s cubic-bezier(.2,0,.2,1)!important}.medium-zoom-image--hidden{visibility:hidden}.medium-zoom-image--opened{position:relative;cursor:pointer;cursor:zoom-out;will-change:transform}";Jp(Qp);const Xp=Symbol("mediumZoom");var Zp={};const eh="[vp-content] > img, [vp-content] :not(a) > img",th=Zp,nh=300,rh=Yt({enhance({app:e,router:t}){const n=Yp(th);n.refresh=(r=eh)=>{n.detach(),n.attach(r)},e.provide(Xp,n),t.afterEach(()=>{xa(nh).then(()=>{n.refresh()})})}}),oh=Object.freeze(Object.defineProperty({__proto__:null,default:rh},Symbol.toStringTag,{value:"Module"}));/** + * NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress + * @license MIT + */const Vi=(e,t)=>{e.classList.add(t)},Hi=(e,t)=>{e.classList.remove(t)},sh=e=>{var t;(t=e==null?void 0:e.parentNode)==null||t.removeChild(e)},Co=(e,t,n)=>en?n:e,$i=e=>(-1+e)*100,ih=(()=>{const e=[],t=()=>{const n=e.shift();n&&n(t)};return n=>{e.push(n),e.length===1&&t()}})(),lh=e=>e.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,(t,n)=>n.toUpperCase()),Tr=(()=>{const e=["Webkit","O","Moz","ms"],t={},n=s=>{const{style:i}=document.body;if(s in i)return s;const l=s.charAt(0).toUpperCase()+s.slice(1);let a=e.length;for(;a--;){const f=`${e[a]}${l}`;if(f in i)return f}return s},r=s=>{const i=lh(s);return t[i]??(t[i]=n(i))},o=(s,i,l)=>{s.style[r(i)]=l};return(s,i)=>{for(const l in i){const a=i[l];Object.hasOwn(i,l)&&Vp(a)&&o(s,l,a)}}})(),Pt={minimum:.08,easing:"ease",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,barSelector:'[role="bar"]',parent:"body",template:'
'},Pe={percent:null,isRendered:()=>!!document.getElementById("nprogress"),set:e=>{const{speed:t,easing:n}=Pt,r=Pe.isStarted(),o=Co(e,Pt.minimum,1);Pe.percent=o===1?null:o;const s=Pe.render(!r),i=s.querySelector(Pt.barSelector);return s.offsetWidth,ih(l=>{Tr(i,{transform:`translate3d(${$i(o)}%,0,0)`,transition:`all ${t}ms ${n}`}),o===1?(Tr(s,{transition:"none",opacity:"1"}),s.offsetWidth,setTimeout(()=>{Tr(s,{transition:`all ${t}ms linear`,opacity:"0"}),setTimeout(()=>{Pe.remove(),l()},t)},t)):setTimeout(()=>{l()},t)}),Pe},isStarted:()=>typeof Pe.percent=="number",start:()=>{Pe.percent||Pe.set(0);const e=()=>{setTimeout(()=>{Pe.percent&&(Pe.trickle(),e())},Pt.trickleSpeed)};return e(),Pe},done:e=>!e&&!Pe.percent?Pe:Pe.increase(.3+.5*Math.random()).set(1),increase:e=>{let{percent:t}=Pe;return t?(t=Co(t+(typeof e=="number"?e:(1-t)*Co(Math.random()*t,.1,.95)),0,.994),Pe.set(t)):Pe.start()},trickle:()=>Pe.increase(Math.random()*Pt.trickleRate),render:e=>{if(Pe.isRendered())return document.getElementById("nprogress");Vi(document.documentElement,"nprogress-busy");const t=document.createElement("div");t.id="nprogress",t.innerHTML=Pt.template;const n=t.querySelector(Pt.barSelector),r=document.querySelector(Pt.parent),o=e?"-100":$i(Pe.percent??0);return Tr(n,{transition:"all 0 linear",transform:`translate3d(${o}%,0,0)`}),r&&(r!==document.body&&Vi(r,"nprogress-custom-parent"),r.appendChild(t)),t},remove:()=>{Hi(document.documentElement,"nprogress-busy"),Hi(document.querySelector(Pt.parent),"nprogress-custom-parent"),sh(document.getElementById("nprogress"))}},ah=()=>{We(()=>{const e=qt(),t=new Set;t.add(e.currentRoute.value.path),e.beforeEach(n=>{t.has(n.path)||Pe.start()}),e.afterEach(n=>{t.add(n.path),Pe.done()})})},ch=Yt({setup(){ah()}}),uh=Object.freeze(Object.defineProperty({__proto__:null,default:ch},Symbol.toStringTag,{value:"Module"})),fh=JSON.parse('{"docsRepo":"needle-tools/needle-engine-support","docsBranch":"main","docsDir":"documentation","logo":"/needle-logo-black.svg","logoDark":"/needle-logo-white.svg","colorModeSwitch":true,"colorMode":"light","lastUpdated":true,"contributors":false,"editLink":true,"editLinkText":"Suggest changes","externalLinkIcon":true,"notFound":["Oh no โ€” this page does not exist!","Gosh! You found a ๐ŸŒต glitch"],"navbar":[{"text":"Overview","link":"/","children":[{"text":"What is Needle Engine?","link":"/"},"/testimonials",{"text":"Get an overview","children":[{"text":"Samples and Showcase","link":"https://engine.needle.tools/samples?utm_source=needle_docs&utm_content=headernav"},"/vision","/features-overview","/technical-overview"]},{"text":"Resources","children":[{"text":"Pricing and Plans","link":"https://needle.tools/pricing/?utm_source=needle_docs&utm_content=headersubnav"},{"text":"Changelog","link":"https://github.com/needle-tools/needle-engine-support/releases"},{"text":"API Documentation","link":"https://engine.needle.tools/docs/api/latest"},{"text":"Get Help","target":"_blank","link":"https://forum.needle.tools/?utm_source=needle_docs&utm_content=headersubnav"}]}]},{"text":"Downloads","link":"/getting-started/"},{"text":"Guides","children":[{"text":"Integrations","children":["/unity/","/blender/","/three/","/embedding/"]},{"text":"Topics","children":["/project-structure","/everywhere-actions","/export","/html","/testing","/deployment"]},{"text":"Advanced","children":["/networking","/xr","/vanilla-js","/unity/editor-sync"]},{"text":"Troubleshooting","children":["/debugging","/faq",{"text":"Get Help","target":"_blank","link":"https://forum.needle.tools/?utm_source=needle_docs&utm_content=headersubnav"}]},{"text":"Videos","children":[{"text":"Tutorials on Youtube","target":"_blank","link":"https://www.youtube.com/playlist?list=PLJ4BaFFEGP1GVTmPhKDC6QzL8Am9700Wo"},{"text":"Interviews on Youtube","target":"_blank","link":"https://www.youtube.com/playlist?list=PLJ4BaFFEGP1EOHCjYszc__d2yO7RkB-iw"}]}]},{"text":"Reference","children":[{"text":"Scripting Overview","children":["/getting-started/typescript-essentials","/getting-started/for-unity-developers","/component-reference","/everywhere-actions"]},{"text":"Components and Lifecycle","children":["/scripting","/reference/typescript-decorators","/component-compiler","/scripting-examples",{"text":"Community Contributions","link":"/community/contributions"},"/modules"]},{"text":"Settings and APIs","children":["/reference/needle-engine-attributes","/reference/needle-config-json",{"text":"Needle Engine API","link":"https://engine.needle.tools/docs/api/latest"},{"text":"three.js API","link":"https://threejs.org/docs/index.html"}]}]},{"text":"Samples","target":"_blank","link":"https://engine.needle.tools/samples?utm_source=needle_docs&utm_content=headernav"},{"text":"Pricing","target":"_blank","link":"https://needle.tools/pricing/?utm_source=needle_docs&utm_content=headernav"},{"text":"Get Help","target":"_blank","link":"https://forum.needle.tools/?utm_source=needle_docs&utm_content=headersubnav"},{"text":"Contact","children":[{"text":"Needle Website","link":"https://needle.tools?utm_source=needle_docs&utm_content=headernav"},{"text":"Support Community","link":"https://forum.needle.tools?utm_source=needle_docs&utm_content=headernav"},{"text":"Discord Server","link":"https://discord.needle.tools"},{"text":"Twitter","link":"https://twitter.com/needletools"},{"text":"Youtube","link":"https://www.youtube.com/@needle-tools"},{"text":"Newsletter","link":"https://fwd.needle.tools/needle-engine/newsletter"},{"text":"Email","link":"mailto:hi+docs@needle.tools"},{"text":"Feedback","link":"https://fwd.needle.tools/needle-engine/feedback"},{"text":"Github","link":"https://github.com/needle-tools"}]}],"sidebarDepth":1,"sidebar":{"/":[{"text":"Getting Started","children":[{"text":"Downloads","link":"/getting-started/"},{"text":"Needle Engine for Unity","link":"/unity/"},{"text":"Needle Engine for Blender","link":"/blender/"},{"text":"Needle Engine as Web Component","link":"/three/"},{"text":"Needle Engine on your Website","link":"/embedding"},{"text":"Custom integrations","link":"/custom-integrations/"},{"text":"Support and Community","link":"/support"}]},{"text":"Core Concepts","children":["/project-structure","/everywhere-actions","/export","/html","/testing","/deployment","/debugging","/faq"]},{"text":"Scripting","children":["/getting-started/typescript-essentials","/getting-started/for-unity-developers","/scripting","/component-compiler","/scripting-examples",{"text":"Community Contributions","link":"/community/contributions/"}]},{"text":"Advanced","children":["/xr","/networking","/unity/editor-sync"]},{"text":"Reference","children":["/features-overview","/technical-overview","/component-reference","/reference/needle-config-json","/reference/needle-engine-attributes","/reference/typescript-decorators"]}]},"locales":{"/":{"selectLanguageName":"English"}},"repo":null,"selectLanguageText":"Languages","selectLanguageAriaLabel":"Select language","lastUpdatedText":"Last Updated","contributorsText":"Contributors","backToHome":"Take me home","openInNewWindow":"open in new window","toggleColorMode":"toggle color mode","toggleSidebar":"toggle sidebar"}'),dh=ge(fh),Ta=()=>dh,ka=Symbol(""),ph=()=>{const e=Fe(ka);if(!e)throw new Error("useThemeLocaleData() is called without provider.");return e},hh=(e,t)=>{const{locales:n,...r}=e;return{...r,...n==null?void 0:n[t]}},mh=Yt({enhance({app:e}){const t=Ta(),n=e._context.provides[gs],r=H(()=>hh(t.value,n.routeLocale.value));e.provide(ka,r),Object.defineProperties(e.config.globalProperties,{$theme:{get(){return t.value}},$themeLocale:{get(){return r.value}}})}}),gh=Object.freeze(Object.defineProperty({__proto__:null,default:mh},Symbol.toStringTag,{value:"Module"})),vh=()=>Ta(),Ie=()=>ph(),Aa=Symbol(""),_h=e=>{const t=(n=e.value)=>{const r=window.document.documentElement;r.dataset.theme=n?"dark":"light"};We(()=>{ze(e,t,{immediate:!0})}),fr(()=>{t()})},lo=()=>{const e=Fe(Aa);if(!e)throw new Error("useDarkMode() is called without provider.");return e},bh=()=>{const e=Ie(),t=Ep(),n=Pa("vuepress-color-scheme",e.value.colorMode),r=H({get(){return e.value.colorModeSwitch?n.value==="auto"?t.value:n.value==="dark":e.value.colorMode==="dark"},set(o){o===t.value?n.value="auto":n.value=o?"dark":"light"}});an(Aa,r),_h(r)};let To=null,$n=null;const yh={wait:()=>To,pending:()=>{To=new Promise(e=>{$n=e})},resolve:()=>{$n==null||$n(),To=null,$n=null}},Oa=()=>yh,kn=(e,t)=>{const{notFound:n,meta:r,path:o}=nr(e,t);return n?{text:o,link:o}:{text:r.title||o,link:o}},Ni=e=>decodeURI(e).replace(/#.*$/,"").replace(/(index)?\.(md|html)$/,""),Eh=(e,t)=>{if(t.hash===e)return!0;const n=Ni(t.path),r=Ni(e);return n===r},Ra=(e,t)=>e.link&&Eh(e.link,t)?!0:"children"in e?e.children.some(n=>Ra(n,t)):!1,Ia=e=>!Of(e)&&!mr(e),Da=e=>!ro(e)||e.includes("github.com")?"GitHub":e.includes("bitbucket.org")?"Bitbucket":e.includes("gitlab.com")?"GitLab":e.includes("gitee.com")?"Gitee":null,wh={GitHub:":repo/edit/:branch/:path",GitLab:":repo/-/edit/:branch/:path",Gitee:":repo/edit/:branch/:path",Bitbucket:":repo/src/:branch/:path?mode=edit&spa=0&at=:branch&fileviewer=file-view-default"},Sh=({docsRepo:e,editLinkPattern:t})=>{if(t)return t;const n=Da(e);return n!==null?wh[n]:null},Ph=({docsRepo:e,docsBranch:t,docsDir:n,filePathRelative:r,editLinkPattern:o})=>{if(!r)return null;const s=Sh({docsRepo:e,editLinkPattern:o});return s?s.replace(/:repo/,ro(e)?e:`https://github.com/${e}`).replace(/:branch/,t).replace(/:path/,ds(`${oa(n)}/${r}`)):null},Ln=(e="",t="")=>Ca(t)||mr(t)?t:`${Bf(e)}${t}`,Dr=ge([]),xh=()=>{const e=qt(),t=Ie(),n=Et(),r=H(()=>n.value.sidebarDepth??t.value.sidebarDepth??2);e.beforeEach((s,i)=>{s.path!==i.path&&(Dr.value=[])});const o=()=>{if(r.value<=0){Dr.value=[];return}Dr.value=Mp({levels:[2,r.value+1],ignore:[".vp-badge"]})};ze(r,o),We(o)},Lh=()=>Dr,Ch=e=>({text:e.title,link:e.link,children:Ps(e.children)}),Ps=e=>e?e.map(t=>Ch(t)):[],Ma=(e,t)=>[{text:e.title,children:Ps(t)}],Va=(e,t,n,r="")=>{const o=(s,i)=>{var a;const l=ut(s)?kn(Ln(i,s)):ut(s.link)?{...s,link:Ia(s.link)?kn(Ln(i,s.link)).link:s.link}:s;if("children"in l)return{...l,children:l.children.map(f=>o(f,Ln(i,l.prefix)))};if(l.link===n){const f=((a=t[0])==null?void 0:a.level)===1?t[0].children:t;return{...l,children:Ps(f)}}return l};return e.map(s=>o(s,r))},Th=(e,t,n,r)=>{const o=Hp(e).sort((s,i)=>i.length-s.length);for(const s of o)if(La(decodeURI(r),s)){const i=e[s];return i?i==="heading"?Ma(t,n):Va(i,n,r,s):[]}return console.warn(`${decodeURI(r)} is missing sidebar config.`),[]},Ha=Symbol("sidebarItems"),xs=()=>{const e=Fe(Ha);if(!e)throw new Error("useSidebarItems() is called without provider.");return e},kh=(e,t,n,r,o)=>e===!1?[]:e==="heading"?Ma(t,o):Array.isArray(e)?Va(e,o,n,r):ps(e)?Th(e,t,o,n):[],Ah=()=>{const e=Ie(),t=Et(),n=On(),r=At(),o=dn(),s=Lh(),i=H(()=>t.value.home?!1:t.value.sidebar??e.value.sidebar??"heading"),l=H(()=>kh(i.value,n.value,r.path,o.value,s.value));an(Ha,l)},Oh=fe({__name:"Badge",props:{type:{default:"tip"},text:{default:""},vertical:{default:void 0}},setup(e,{expose:t}){t();const n={};return Object.defineProperty(n,"__isScriptSetup",{enumerable:!1,value:!0}),n}}),we=(e,t)=>{const n=e.__vccOpts||e;for(const[r,o]of t)n[r]=o;return n};function Rh(e,t,n,r,o,s){return K(),ee("span",{class:Qe(["vp-badge",n.type]),style:ir({verticalAlign:n.vertical})},[xe(e.$slots,"default",{},()=>[zt(Le(n.text),1)])],6)}const Ih=we(Oh,[["render",Rh],["__file","Badge.vue"]]),Dh=fe({name:"CodeGroup",slots:Object,setup(e,{slots:t}){const n=ge([]),r=lo(),o=ge();We(()=>{if(!o.value)return;const c=o.value.querySelector('div[class*="language-"]');if(c&&c.dataset.highlighter==="shiki"){const p=c.style.getPropertyValue("--shiki-light"),m=c.style.getPropertyValue("--shiki-dark"),v=c.style.getPropertyValue("--shiki-light-bg"),y=c.style.getPropertyValue("--shiki-dark-bg");ze(r,C=>{o.value.style.setProperty("--vp-c-code-tab-bg",C?y:v),o.value.style.setProperty("--vp-c-code-tab-title",C?m:p)},{immediate:!0})}});const s=ge(-1),i=Pa("vuepress-code-group",{}),l=H(()=>n.value.map(c=>c.innerText).join(","));We(()=>{ze(()=>i.value[l.value],(c=-1)=>{s.value!==c&&(s.value=c)},{immediate:!0}),ze(s,c=>{i.value[l.value]!==c&&(i.value[l.value]=c)})});const a=(c=s.value)=>{c{c>0?s.value=c-1:s.value=n.value.length-1,n.value[s.value].focus()},u=(c,p)=>{c.key===" "||c.key==="Enter"?(c.preventDefault(),s.value=p):c.key==="ArrowRight"?(c.preventDefault(),a(p)):c.key==="ArrowLeft"&&(c.preventDefault(),f(p))};return()=>{var p;const c=(((p=t.default)==null?void 0:p.call(t))??[]).filter(m=>m.type.name==="CodeGroupItem").map(m=>(m.props===null&&(m.props={}),m));return c.length===0?null:(s.value<0||s.value>c.length-1?(s.value=c.findIndex(m=>m.props.active===""||m.props.active===!0),s.value===-1&&(s.value=0)):c.forEach((m,v)=>{m.props.active=v===s.value}),Ve("div",{class:"code-group",ref:o},[Ve("div",{class:"code-group-nav",role:"tablist"},c.map((m,v)=>{const y=v===s.value;return Ve("button",{ref:C=>{C&&(n.value[v]=C)},class:{"code-group-nav-tab":!0,active:y},role:"tab",ariaSelected:y,onClick:()=>{s.value=v},onKeydown:C=>{u(C,v)}},m.props.title)})),c]))}}}),Mh=fe({name:"CodeGroupItem",__name:"CodeGroupItem",props:{title:{},active:{type:Boolean}},setup(e,{expose:t}){t();const n={};return Object.defineProperty(n,"__isScriptSetup",{enumerable:!1,value:!0}),n}});function Vh(e,t,n,r,o,s){return K(),ee("div",{class:Qe(["code-group-item",{active:n.active}]),role:"tabpanel"},[xe(e.$slots,"default")],2)}const Hh=we(Mh,[["render",Vh],["__file","CodeGroupItem.vue"]]),$h=fe({__name:"VPHomeFeatures",setup(e,{expose:t}){t();const n=Et(),r=H(()=>n.value.features??[]),o={frontmatter:n,features:r};return Object.defineProperty(o,"__isScriptSetup",{enumerable:!1,value:!0}),o}}),Nh={key:0,class:"vp-features"};function jh(e,t,n,r,o,s){return r.features.length?(K(),ee("div",Nh,[(K(!0),ee(me,null,Bt(r.features,i=>(K(),ee("div",{key:i.title,class:"vp-feature"},[re("h2",null,Le(i.title),1),re("p",null,Le(i.details),1)]))),128))])):Ae("",!0)}const Bh=we($h,[["render",jh],["__file","VPHomeFeatures.vue"]]),Fh=fe({__name:"VPHomeFooter",setup(e,{expose:t}){t();const n=Et(),r=H(()=>n.value.footer),o=H(()=>n.value.footerHtml),s={frontmatter:n,footer:r,footerHtml:o};return Object.defineProperty(s,"__isScriptSetup",{enumerable:!1,value:!0}),s}}),zh=["innerHTML"],Uh=["textContent"];function Wh(e,t,n,r,o,s){return r.footer?(K(),ee(me,{key:0},[r.footerHtml?(K(),ee("div",{key:0,class:"vp-footer","vp-footer":"",innerHTML:r.footer},null,8,zh)):(K(),ee("div",{key:1,class:"vp-footer","vp-footer":"",textContent:Le(r.footer)},null,8,Uh))],64)):Ae("",!0)}const Kh=we(Fh,[["render",Wh],["__file","VPHomeFooter.vue"]]),Gh=fe({__name:"VPHomeHero",setup(e,{expose:t}){t();const n=Et(),r=vs(),o=lo(),s=H(()=>n.value.heroText===null?null:n.value.heroText||r.value.title||"Hello"),i=H(()=>n.value.tagline===null?null:n.value.tagline||r.value.description||"Welcome to your VuePress site"),l=H(()=>o.value&&n.value.heroImageDark!==void 0?n.value.heroImageDark:n.value.heroImage),a=H(()=>n.value.heroAlt||s.value||"hero"),f=H(()=>n.value.heroHeight??280),u=H(()=>Array.isArray(n.value.actions)?n.value.actions.map(({text:m,link:v,type:y="primary"})=>({text:m,link:v,type:y})):[]),p={frontmatter:n,siteLocale:r,isDarkMode:o,heroText:s,tagline:i,heroImage:l,heroAlt:a,heroHeight:f,actions:u,HomeHeroImage:()=>{if(!l.value)return null;const m=Ve("img",{class:"vp-hero-image",src:ys(l.value),alt:a.value,height:f.value});return n.value.heroImageDark===void 0?m:Ve(_s,()=>m)},get AutoLink(){return Rn}};return Object.defineProperty(p,"__isScriptSetup",{enumerable:!1,value:!0}),p}}),qh={class:"vp-hero"},Yh={key:0,id:"main-title"},Jh={key:1,class:"vp-hero-description"},Qh={key:2,class:"vp-hero-actions"};function Xh(e,t,n,r,o,s){return K(),ee("header",qh,[se(r.HomeHeroImage),r.heroText?(K(),ee("h1",Yh,Le(r.heroText),1)):Ae("",!0),r.tagline?(K(),ee("p",Jh,Le(r.tagline),1)):Ae("",!0),r.actions.length?(K(),ee("p",Qh,[(K(!0),ee(me,null,Bt(r.actions,i=>(K(),Ce(r.AutoLink,{key:i.text,class:Qe(["vp-hero-action-button",[i.type]]),config:i},null,8,["class","config"]))),128))])):Ae("",!0)])}const Zh=we(Gh,[["render",Xh],["__file","VPHomeHero.vue"]]),em=fe({__name:"VPHome",setup(e,{expose:t}){t();const n={VPHomeFeatures:Bh,VPHomeFooter:Kh,VPHomeHero:Zh,get Content(){return bs}};return Object.defineProperty(n,"__isScriptSetup",{enumerable:!1,value:!0}),n}}),tm={class:"vp-home"},nm={class:"theme-default-content","vp-content":""};function rm(e,t,n,r,o,s){return K(),ee("main",tm,[se(r.VPHomeHero),se(r.VPHomeFeatures),re("div",nm,[se(r.Content)]),se(r.VPHomeFooter)])}const om=we(em,[["render",rm],["__file","VPHome.vue"]]),sm=fe({__name:"VPNavbarBrand",setup(e,{expose:t}){t();const n=dn(),r=vs(),o=Ie(),s=lo(),i=H(()=>o.value.home||n.value),l=H(()=>r.value.title),a=H(()=>s.value&&o.value.logoDark!==void 0?o.value.logoDark:o.value.logo),f=H(()=>o.value.logoAlt??l.value),u=H(()=>l.value.toLocaleUpperCase().trim()===f.value.toLocaleUpperCase().trim()),p={routeLocale:n,siteLocale:r,themeLocale:o,isDarkMode:s,navbarBrandLink:i,navbarBrandTitle:l,navbarBrandLogo:a,navbarBrandLogoAlt:f,navBarLogoAltMatchesTitle:u,NavbarBrandLogo:()=>{if(!a.value)return null;const m=Ve("img",{class:"vp-site-logo",src:ys(a.value),alt:f.value});return o.value.logoDark===void 0?m:Ve(_s,()=>m)},get RouteLink(){return io}};return Object.defineProperty(p,"__isScriptSetup",{enumerable:!1,value:!0}),p}}),im=["aria-hidden"];function lm(e,t,n,r,o,s){return K(),Ce(r.RouteLink,{to:r.navbarBrandLink},{default:ke(()=>[se(r.NavbarBrandLogo),r.navbarBrandTitle?(K(),ee("span",{key:0,class:Qe(["vp-site-name",{"vp-hide-mobile":r.navbarBrandLogo}]),"aria-hidden":r.navBarLogoAltMatchesTitle},Le(r.navbarBrandTitle),11,im)):Ae("",!0)]),_:1},8,["to"])}const am=we(sm,[["render",lm],["__file","VPNavbarBrand.vue"]]),cm=fe({__name:"VPDropdownTransition",setup(e,{expose:t}){t();const o={setHeight:s=>{s.style.height=`${s.scrollHeight}px`},unsetHeight:s=>{s.style.height=""}};return Object.defineProperty(o,"__isScriptSetup",{enumerable:!1,value:!0}),o}});function um(e,t,n,r,o,s){return K(),Ce(ea,{name:"vp-dropdown",onEnter:r.setHeight,onAfterEnter:r.unsetHeight,onBeforeLeave:r.setHeight},{default:ke(()=>[xe(e.$slots,"default")]),_:3})}const $a=we(cm,[["render",um],["__file","VPDropdownTransition.vue"]]),fm=fe({__name:"VPNavbarDropdown",props:{item:{}},setup(e,{expose:t}){t();const n=e,{item:r}=hl(n),o=At(),s=ge(!1),i=H(()=>r.value.ariaLabel||r.value.text),l=(u,c)=>c[c.length-1]===u,a=u=>{const c=u.detail===0;s.value=c?!s.value:!1};ze(()=>o.path,()=>{s.value=!1});const f={props:n,item:r,route:o,open:s,dropdownAriaLabel:i,isLastItemOfArray:l,handleDropdown:a,VPDropdownTransition:$a,get AutoLink(){return Rn}};return Object.defineProperty(f,"__isScriptSetup",{enumerable:!1,value:!0}),f}}),dm=["aria-label"],pm={class:"title"},hm=["aria-label"],mm={class:"title"},gm={class:"vp-navbar-dropdown"},vm={class:"vp-navbar-dropdown-subtitle"},_m={key:1},bm={class:"vp-navbar-dropdown-subitem-wrapper"};function ym(e,t,n,r,o,s){return K(),ee("div",{class:Qe(["vp-navbar-dropdown-wrapper",{open:r.open}])},[re("button",{class:"vp-navbar-dropdown-title",type:"button","aria-label":r.dropdownAriaLabel,onClick:r.handleDropdown},[re("span",pm,Le(r.item.text),1),t[1]||(t[1]=re("span",{class:"arrow down"},null,-1))],8,dm),re("button",{class:"vp-navbar-dropdown-title-mobile",type:"button","aria-label":r.dropdownAriaLabel,onClick:t[0]||(t[0]=i=>r.open=!r.open)},[re("span",mm,Le(r.item.text),1),re("span",{class:Qe(["arrow",r.open?"down":"right"])},null,2)],8,hm),se(r.VPDropdownTransition,null,{default:ke(()=>[$r(re("ul",gm,[(K(!0),ee(me,null,Bt(r.item.children,i=>(K(),ee("li",{key:i.text,class:"vp-navbar-dropdown-item"},["children"in i?(K(),ee(me,{key:0},[re("h4",vm,[i.link?(K(),Ce(r.AutoLink,{key:0,config:i,onFocusout:l=>r.isLastItemOfArray(i,r.item.children)&&i.children.length===0&&(r.open=!1)},null,8,["config","onFocusout"])):(K(),ee("span",_m,Le(i.text),1))]),re("ul",bm,[(K(!0),ee(me,null,Bt(i.children,l=>(K(),ee("li",{key:l.link,class:"vp-navbar-dropdown-subitem"},[se(r.AutoLink,{config:l,onFocusout:a=>r.isLastItemOfArray(l,i.children)&&r.isLastItemOfArray(i,r.item.children)&&(r.open=!1)},null,8,["config","onFocusout"])]))),128))])],64)):(K(),Ce(r.AutoLink,{key:1,config:i,onFocusout:l=>r.isLastItemOfArray(i,r.item.children)&&(r.open=!1)},null,8,["config","onFocusout"]))]))),128))],512),[[Ur,r.open]])]),_:1})],2)}const Em=we(fm,[["render",ym],["__file","VPNavbarDropdown.vue"]]),Na=(e,t="")=>ut(e)?kn(Ln(t,e)):"children"in e?{...e,children:e.children.map(n=>Na(n,Ln(t,e.prefix)))}:{...e,link:Ia(e.link)?kn(Ln(t,e.link)).link:e.link},wm=()=>{const e=Ie();return H(()=>(e.value.navbar||[]).map(t=>Na(t)))},Sm=()=>{const e=Ie(),t=H(()=>e.value.repo),n=H(()=>t.value?Da(t.value):null),r=H(()=>t.value&&!ro(t.value)?`https://github.com/${t.value}`:t.value),o=H(()=>r.value?e.value.repoLabel?e.value.repoLabel:n.value===null?"Source":n.value:null);return H(()=>!r.value||!o.value?[]:[{text:o.value,link:r.value}])},Pm=()=>{const e=At(),t=Rp(),n=dn(),r=_a(),o=vs(),s=vh(),i=Ie();return H(()=>{const l=Object.keys(r.value.locales);if(l.length<2)return[];const a=e.path,f=e.fullPath;return[{text:`${i.value.selectLanguageText}`,ariaLabel:`${i.value.selectLanguageAriaLabel??i.value.selectLanguageText}`,children:l.map(c=>{var T,S;const p=((T=r.value.locales)==null?void 0:T[c])??{},m=((S=s.value.locales)==null?void 0:S[c])??{},v=`${p.lang}`,y=m.selectLanguageName??v;if(v===o.value.lang)return{text:y,activeMatch:".",link:e.fullPath};const C=a.replace(n.value,c);return{text:y,link:t.value.some(g=>g===C)?f.replace(a,C):m.home??c}})}]})},xm="719px",Lm={mobile:xm};var rr;(function(e){e.Mobile="mobile"})(rr||(rr={}));const Cm={[rr.Mobile]:Number.parseInt(Lm.mobile.replace("px",""),10)},ja=(e,t)=>{const n=Cm[e];Number.isInteger(n)&&(bt("orientationchange",()=>{t(n)},!1),bt("resize",()=>{t(n)},!1),We(()=>{t(n)}))},Tm=fe({__name:"VPNavbarItems",setup(e,{expose:t}){t();const n=wm(),r=Pm(),o=Sm(),s=ge(!1),i=H(()=>Ie().value.navbarLabel??"site navigation"),l=H(()=>[...n.value,...r.value,...o.value]);ja(rr.Mobile,f=>{s.value=window.innerWidth(K(),ee("div",{key:i.text,class:"vp-navbar-item"},["children"in i?(K(),Ce(r.VPNavbarDropdown,{key:0,class:Qe({mobile:r.isMobile}),item:i},null,8,["class","item"])):(K(),Ce(r.AutoLink,{key:1,config:i},null,8,["config"]))]))),128))],8,km)):Ae("",!0)}const Ba=we(Tm,[["render",Am],["__file","VPNavbarItems.vue"]]),Om={},Rm={class:"dark-icon",viewBox:"0 0 32 32"};function Im(e,t){return K(),ee("svg",Rm,t[0]||(t[0]=[re("path",{d:"M13.502 5.414a15.075 15.075 0 0 0 11.594 18.194a11.113 11.113 0 0 1-7.975 3.39c-.138 0-.278.005-.418 0a11.094 11.094 0 0 1-3.2-21.584M14.98 3a1.002 1.002 0 0 0-.175.016a13.096 13.096 0 0 0 1.825 25.981c.164.006.328 0 .49 0a13.072 13.072 0 0 0 10.703-5.555a1.01 1.01 0 0 0-.783-1.565A13.08 13.08 0 0 1 15.89 4.38A1.015 1.015 0 0 0 14.98 3z",fill:"currentColor"},null,-1)]))}const Dm=we(Om,[["render",Im],["__file","VPDarkIcon.vue"]]),Mm={},Vm={class:"light-icon",viewBox:"0 0 32 32"};function Hm(e,t){return K(),ee("svg",Vm,t[0]||(t[0]=[Nu('',9)]))}const $m=we(Mm,[["render",Hm],["__file","VPLightIcon.vue"]]),Nm=fe({__name:"VPToggleColorModeButton",setup(e,{expose:t}){t();const n=Ie(),r=lo(),s={themeLocale:n,isDarkMode:r,toggleColorMode:()=>{r.value=!r.value},VPDarkIcon:Dm,VPLightIcon:$m};return Object.defineProperty(s,"__isScriptSetup",{enumerable:!1,value:!0}),s}}),jm=["title"];function Bm(e,t,n,r,o,s){return K(),ee("button",{type:"button",class:"vp-toggle-color-mode-button",title:r.themeLocale.toggleColorMode,onClick:r.toggleColorMode},[$r(se(r.VPLightIcon,null,null,512),[[Ur,!r.isDarkMode]]),$r(se(r.VPDarkIcon,null,null,512),[[Ur,r.isDarkMode]])],8,jm)}const Fm=we(Nm,[["render",Bm],["__file","VPToggleColorModeButton.vue"]]),zm=fe({__name:"VPToggleSidebarButton",emits:["toggle"],setup(e,{expose:t}){t();const r={themeLocale:Ie()};return Object.defineProperty(r,"__isScriptSetup",{enumerable:!1,value:!0}),r}}),Um=["title"];function Wm(e,t,n,r,o,s){return K(),ee("div",{class:"vp-toggle-sidebar-button",title:r.themeLocale.toggleSidebar,"aria-expanded":"false",role:"button",tabindex:"0",onClick:t[0]||(t[0]=i=>e.$emit("toggle"))},t[1]||(t[1]=[re("div",{class:"icon","aria-hidden":"true"},[re("span"),re("span"),re("span")],-1)]),8,Um)}const Km=we(zm,[["render",Wm],["__file","VPToggleSidebarButton.vue"]]),Gm=fe({__name:"VPNavbar",emits:["toggleSidebar"],setup(e,{expose:t}){t();const n=Rr("SearchBox")?as("SearchBox"):null,r=Ie(),o=ge(null),s=ge(null),i=ge(0),l=H(()=>i.value?{maxWidth:`${i.value}px`}:{}),a=(u,c)=>{var v;const p=(v=u==null?void 0:u.ownerDocument.defaultView)==null?void 0:v.getComputedStyle(u,null)[c],m=Number.parseInt(p,10);return Number.isNaN(m)?0:m};ja(rr.Mobile,u=>{var p;const c=a(o.value,"paddingLeft")+a(o.value,"paddingRight");window.innerWidthe.$emit("toggleSidebar"))}),re("span",Ym,[se(r.VPNavbarBrand)],512),re("div",{class:"vp-navbar-items-wrapper",style:ir(r.linksWrapperStyle)},[xe(e.$slots,"before"),se(r.VPNavbarItems,{class:"vp-hide-mobile"}),xe(e.$slots,"after"),r.themeLocale.colorModeSwitch?(K(),Ce(r.VPToggleColorModeButton,{key:0})):Ae("",!0),se(r.SearchBox)],4)],512)}const Qm=we(Gm,[["render",Jm],["__file","VPNavbar.vue"]]),Xm={},Zm={class:"edit-icon",viewBox:"0 0 1024 1024"};function eg(e,t){return K(),ee("svg",Zm,t[0]||(t[0]=[re("g",{fill:"currentColor"},[re("path",{d:"M430.818 653.65a60.46 60.46 0 0 1-50.96-93.281l71.69-114.012 7.773-10.365L816.038 80.138A60.46 60.46 0 0 1 859.225 62a60.46 60.46 0 0 1 43.186 18.138l43.186 43.186a60.46 60.46 0 0 1 0 86.373L588.879 565.55l-8.637 8.637-117.466 68.234a60.46 60.46 0 0 1-31.958 11.229z"}),re("path",{d:"M728.802 962H252.891A190.883 190.883 0 0 1 62.008 771.98V296.934a190.883 190.883 0 0 1 190.883-192.61h267.754a60.46 60.46 0 0 1 0 120.92H252.891a69.962 69.962 0 0 0-69.098 69.099V771.98a69.962 69.962 0 0 0 69.098 69.098h475.911A69.962 69.962 0 0 0 797.9 771.98V503.363a60.46 60.46 0 1 1 120.922 0V771.98A190.883 190.883 0 0 1 728.802 962z"})],-1)]))}const tg=we(Xm,[["render",eg],["__file","VPEditIcon.vue"]]),ng=()=>{const e=Ie(),t=On(),n=Et();return H(()=>{var o;return n.value.contributors??e.value.contributors??!0?((o=t.value.git)==null?void 0:o.contributors)??null:null})},rg=()=>{const e=Ie(),t=On(),n=Et();return H(()=>{if(!(n.value.editLink??e.value.editLink??!0))return null;const{repo:o,docsRepo:s=o,docsBranch:i="main",docsDir:l="",editLinkText:a}=e.value;if(!s)return null;const f=Ph({docsRepo:s,docsBranch:i,docsDir:l,filePathRelative:t.value.filePathRelative,editLinkPattern:n.value.editLinkPattern??e.value.editLinkPattern});return f?{text:a??"Edit this page",link:f}:null})},og=()=>{const e=Ie(),t=On(),n=Et();return H(()=>{var s;return!(n.value.lastUpdated??e.value.lastUpdated??!0)||!((s=t.value.git)!=null&&s.updatedTime)?null:new Date(t.value.git.updatedTime).toLocaleString()})},sg=fe({__name:"VPPageMeta",setup(e,{expose:t}){t();const n=Ie(),r=rg(),o=og(),s=ng(),i={themeLocale:n,editLink:r,lastUpdated:o,contributors:s,VPEditIcon:tg,get AutoLink(){return Rn}};return Object.defineProperty(i,"__isScriptSetup",{enumerable:!1,value:!0}),i}}),ig={class:"vp-page-meta"},lg={key:0,class:"vp-meta-item edit-link"},ag={class:"vp-meta-item git-info"},cg={key:0,class:"vp-meta-item last-updated"},ug={class:"meta-item-label"},fg={class:"meta-item-info"},dg={key:1,class:"vp-meta-item contributors"},pg={class:"meta-item-label"},hg={class:"meta-item-info"},mg=["title"];function gg(e,t,n,r,o,s){const i=as("ClientOnly");return K(),ee("footer",ig,[r.editLink?(K(),ee("div",lg,[se(r.AutoLink,{class:"label",config:r.editLink},{before:ke(()=>[se(r.VPEditIcon)]),_:1},8,["config"])])):Ae("",!0),re("div",ag,[r.lastUpdated?(K(),ee("div",cg,[re("span",ug,Le(r.themeLocale.lastUpdatedText)+": ",1),se(i,null,{default:ke(()=>[re("span",fg,Le(r.lastUpdated),1)]),_:1})])):Ae("",!0),r.contributors&&r.contributors.length?(K(),ee("div",dg,[re("span",pg,Le(r.themeLocale.contributorsText)+": ",1),re("span",hg,[(K(!0),ee(me,null,Bt(r.contributors,(l,a)=>(K(),ee(me,{key:a},[re("span",{class:"contributor",title:`email: ${l.email}`},Le(l.name),9,mg),a!==r.contributors.length-1?(K(),ee(me,{key:0},[zt(", ")],64)):Ae("",!0)],64))),128))])])):Ae("",!0)])])}const vg=we(sg,[["render",gg],["__file","VPPageMeta.vue"]]),_g=()=>{const e=qt(),t=At();return n=>{n&&(Ca(n)?t.path!==n&&e.push(n):mr(n)?window.open(n):e.push(encodeURI(n)))}},ji=(e,t)=>e===!1?!1:ut(e)?kn(e,t):ps(e)?{...e,link:kn(e.link,t).link}:null,Wo=(e,t,n)=>{const r=e.findIndex(s=>s.link===t);if(r!==-1){const s=e[r+n];return s?s.link?s:"prefix"in s&&!nr(s.prefix).notFound?{...s,link:s.prefix}:null:null}for(const s of e)if("children"in s){const i=Wo(s.children,t,n);if(i)return i}const o=e.findIndex(s=>"prefix"in s&&s.prefix===t);if(o!==-1){const s=e[o+n];return s?s.link?s:"prefix"in s&&!nr(s.prefix).notFound?{...s,link:s.prefix}:null:null}return null},bg=()=>{const e=Et(),t=Ie(),n=xs(),r=At(),o=H(()=>{const i=ji(e.value.prev,r.path);return i===!1?null:i??(t.value.prev===!1?null:Wo(n.value,r.path,-1))}),s=H(()=>{const i=ji(e.value.next,r.path);return i===!1?null:i??(t.value.next===!1?null:Wo(n.value,r.path,1))});return{prevLink:o,nextLink:s}},yg=fe({__name:"VPPageNav",setup(e,{expose:t}){t();const n=Ie(),r=_g(),{prevLink:o,nextLink:s}=bg(),i=H(()=>n.value.pageNavbarLabel??"page navigation");bt("keydown",a=>{a.altKey&&(a.key==="ArrowRight"?s.value&&(r(s.value.link),a.preventDefault()):a.key==="ArrowLeft"&&o.value&&(r(o.value.link),a.preventDefault()))});const l={themeLocale:n,navigate:r,prevLink:o,nextLink:s,navbarLabel:i,get AutoLink(){return Rn}};return Object.defineProperty(l,"__isScriptSetup",{enumerable:!1,value:!0}),l}}),Eg=["aria-label"],wg={class:"hint"},Sg={class:"link"},Pg={class:"hint"},xg={class:"link"};function Lg(e,t,n,r,o,s){return r.prevLink||r.nextLink?(K(),ee("nav",{key:0,class:"vp-page-nav","aria-label":r.navbarLabel},[r.prevLink?(K(),Ce(r.AutoLink,{key:0,class:"prev",config:r.prevLink},{default:ke(()=>[re("div",wg,[t[0]||(t[0]=re("span",{class:"arrow left"},null,-1)),zt(" "+Le(r.themeLocale.prev??"Prev"),1)]),re("div",Sg,[re("span",null,Le(r.prevLink.text),1)])]),_:1},8,["config"])):Ae("",!0),r.nextLink?(K(),Ce(r.AutoLink,{key:1,class:"next",config:r.nextLink},{default:ke(()=>[re("div",Pg,[zt(Le(r.themeLocale.next??"Next")+" ",1),t[1]||(t[1]=re("span",{class:"arrow right"},null,-1))]),re("div",xg,[re("span",null,Le(r.nextLink.text),1)])]),_:1},8,["config"])):Ae("",!0)],8,Eg)):Ae("",!0)}const Cg=we(yg,[["render",Lg],["__file","VPPageNav.vue"]]),Tg=fe({__name:"VPPage",setup(e,{expose:t}){t(),xh();const n={VPPageMeta:vg,VPPageNav:Cg,get Content(){return bs}};return Object.defineProperty(n,"__isScriptSetup",{enumerable:!1,value:!0}),n}}),kg={class:"vp-page"},Ag={class:"theme-default-content","vp-content":""};function Og(e,t,n,r,o,s){return K(),ee("main",kg,[xe(e.$slots,"top"),re("div",Ag,[xe(e.$slots,"content-top"),se(r.Content),xe(e.$slots,"content-bottom")]),se(r.VPPageMeta),se(r.VPPageNav),xe(e.$slots,"bottom")])}const Rg=we(Tg,[["render",Og],["__file","VPPage.vue"]]),Ig=fe({__name:"VPSidebarItem",props:{item:{},depth:{default:0}},setup(e,{expose:t}){t();const n=e,{item:r,depth:o}=hl(n),s=At(),i=qt(),l=H(()=>"collapsible"in r.value&&r.value.collapsible),a=H(()=>Ra(r.value,s)),f=H(()=>({"vp-sidebar-item":!0,"vp-sidebar-heading":o.value===0,active:a.value,collapsible:l.value})),u=H(()=>l.value?a.value:!0),[c,p]=hp(u.value),m=C=>{l.value&&(C.preventDefault(),p())},v=i.afterEach(()=>{An(()=>{c.value=u.value})});ls(()=>{v()});const y={props:n,item:r,depth:o,route:s,router:i,collapsible:l,isActive:a,itemClass:f,isOpenDefault:u,isOpen:c,toggleIsOpen:p,onClick:m,unregisterRouterHook:v,VPDropdownTransition:$a,get AutoLink(){return Rn}};return Object.defineProperty(y,"__isScriptSetup",{enumerable:!1,value:!0}),y}}),Dg={class:"vp-sidebar-children"};function Mg(e,t,n,r,o,s){const i=as("VPSidebarItem",!0);return K(),ee("li",null,[r.item.link?(K(),Ce(r.AutoLink,{key:0,class:Qe(r.itemClass),config:r.item},null,8,["class","config"])):(K(),ee("p",{key:1,tabindex:"0",class:Qe(r.itemClass),onClick:r.onClick,onKeydown:Pf(r.onClick,["enter"])},[zt(Le(r.item.text)+" ",1),r.collapsible?(K(),ee("span",{key:0,class:Qe(["arrow",r.isOpen?"down":"right"])},null,2)):Ae("",!0)],34)),"children"in r.item&&r.item.children.length?(K(),Ce(r.VPDropdownTransition,{key:2},{default:ke(()=>[$r(re("ul",Dg,[(K(!0),ee(me,null,Bt(r.item.children,l=>(K(),Ce(i,{key:`${r.depth}${l.text}${l.link}`,item:l,depth:r.depth+1},null,8,["item","depth"]))),128))],512),[[Ur,r.isOpen]])]),_:1})):Ae("",!0)])}const Vg=we(Ig,[["render",Mg],["__file","VPSidebarItem.vue"]]),Hg=fe({__name:"VPSidebarItems",setup(e,{expose:t}){t();const n=At(),r=xs();We(()=>{ze(()=>n.hash,s=>{const i=document.querySelector(".vp-sidebar");if(!i)return;const l=document.querySelector(`.vp-sidebar a.vp-sidebar-item[href="${n.path}${s}"]`);if(!l)return;const{top:a,height:f}=i.getBoundingClientRect(),{top:u,height:c}=l.getBoundingClientRect();ua+f&&l.scrollIntoView(!1)})});const o={route:n,sidebarItems:r,VPSidebarItem:Vg};return Object.defineProperty(o,"__isScriptSetup",{enumerable:!1,value:!0}),o}}),$g={key:0,class:"vp-sidebar-items"};function Ng(e,t,n,r,o,s){return r.sidebarItems.length?(K(),ee("ul",$g,[(K(!0),ee(me,null,Bt(r.sidebarItems,i=>(K(),Ce(r.VPSidebarItem,{key:`${i.text}${i.link}`,item:i},null,8,["item"]))),128))])):Ae("",!0)}const jg=we(Hg,[["render",Ng],["__file","VPSidebarItems.vue"]]),Bg=fe({__name:"VPSidebar",setup(e,{expose:t}){t();const n={VPNavbarItems:Ba,VPSidebarItems:jg};return Object.defineProperty(n,"__isScriptSetup",{enumerable:!1,value:!0}),n}}),Fg={class:"vp-sidebar","vp-sidebar":""};function zg(e,t,n,r,o,s){return K(),ee("aside",Fg,[se(r.VPNavbarItems),xe(e.$slots,"top"),se(r.VPSidebarItems),xe(e.$slots,"bottom")])}const Ug=we(Bg,[["render",zg],["__file","VPSidebar.vue"]]),Wg=fe({__name:"Layout",setup(e,{expose:t}){t();const n=On(),r=Et(),o=Ie(),s=H(()=>r.value.navbar!==!1&&o.value.navbar!==!1),i=xs(),l=ge(!1),a=g=>{l.value=typeof g=="boolean"?g:!l.value},f={x:0,y:0},u=g=>{f.x=g.changedTouches[0].clientX,f.y=g.changedTouches[0].clientY},c=g=>{const b=g.changedTouches[0].clientX-f.x,V=g.changedTouches[0].clientY-f.y;Math.abs(b)>Math.abs(V)&&Math.abs(b)>40&&(b>0&&f.x<=80?a(!0):a(!1))},p=H(()=>r.value.externalLinkIcon??o.value.externalLinkIcon??!0),m=H(()=>[{"no-navbar":!s.value,"no-sidebar":!i.value.length,"sidebar-open":l.value,"external-link-icon":p.value},r.value.pageClass]);let v;We(()=>{v=qt().afterEach(()=>{a(!1)})}),fr(()=>{v()});const y=Oa(),C=y.resolve,T=y.pending,S={page:n,frontmatter:r,themeLocale:o,shouldShowNavbar:s,sidebarItems:i,isSidebarOpen:l,toggleSidebar:a,touchStart:f,onTouchStart:u,onTouchEnd:c,enableExternalLinkIcon:p,containerClass:m,get unregisterRouterHook(){return v},set unregisterRouterHook(g){v=g},scrollPromise:y,onBeforeEnter:C,onBeforeLeave:T,VPHome:om,VPNavbar:Qm,VPPage:Rg,VPSidebar:Ug};return Object.defineProperty(S,"__isScriptSetup",{enumerable:!1,value:!0}),S}});function Kg(e,t,n,r,o,s){return K(),ee("div",{class:Qe(["vp-theme-container",r.containerClass]),"vp-container":"",onTouchstart:r.onTouchStart,onTouchend:r.onTouchEnd},[xe(e.$slots,"navbar",{},()=>[r.shouldShowNavbar?(K(),Ce(r.VPNavbar,{key:0,onToggleSidebar:r.toggleSidebar},{before:ke(()=>[xe(e.$slots,"navbar-before")]),after:ke(()=>[xe(e.$slots,"navbar-after")]),_:3})):Ae("",!0)]),re("div",{class:"vp-sidebar-mask",onClick:t[0]||(t[0]=i=>r.toggleSidebar(!1))}),xe(e.$slots,"sidebar",{},()=>[se(r.VPSidebar,null,{top:ke(()=>[xe(e.$slots,"sidebar-top")]),bottom:ke(()=>[xe(e.$slots,"sidebar-bottom")]),_:3})]),xe(e.$slots,"page",{},()=>[r.frontmatter.home?(K(),Ce(r.VPHome,{key:0})):(K(),Ce(ea,{key:1,name:"fade-slide-y",mode:"out-in",onBeforeEnter:r.onBeforeEnter,onBeforeLeave:r.onBeforeLeave},{default:ke(()=>[(K(),Ce(r.VPPage,{key:r.page.path},{top:ke(()=>[xe(e.$slots,"page-top")]),"content-top":ke(()=>[xe(e.$slots,"page-content-top")]),"content-bottom":ke(()=>[xe(e.$slots,"page-content-bottom")]),bottom:ke(()=>[xe(e.$slots,"page-bottom")]),_:3}))]),_:3},8,["onBeforeEnter","onBeforeLeave"]))])],34)}const Gg=we(Wg,[["render",Kg],["__file","Layout.vue"]]),qg=fe({__name:"NotFound",setup(e,{expose:t}){t();const n=dn(),r=Ie(),o=r.value.notFound??["Not Found"],s=()=>o[Math.floor(Math.random()*o.length)],i=r.value.home??n.value,l=r.value.backToHome??"Back to home",a={routeLocale:n,themeLocale:r,messages:o,getMsg:s,homeLink:i,homeText:l,get RouteLink(){return io}};return Object.defineProperty(a,"__isScriptSetup",{enumerable:!1,value:!0}),a}}),Yg={class:"vp-theme-container","vp-container":""},Jg={class:"page"},Qg={class:"theme-default-content","vp-content":""};function Xg(e,t,n,r,o,s){return K(),ee("div",Yg,[re("main",Jg,[re("div",Qg,[t[0]||(t[0]=re("h1",null,"404",-1)),re("blockquote",null,Le(r.getMsg()),1),se(r.RouteLink,{to:r.homeLink},{default:ke(()=>[zt(Le(r.homeText),1)]),_:1},8,["to"])])])])}const Zg=we(qg,[["render",Xg],["__scopeId","data-v-463c2c5d"],["__file","NotFound.vue"]]),ev=Yt({enhance({app:e,router:t}){Rr("Badge")||e.component("Badge",Ih),Rr("CodeGroup")||e.component("CodeGroup",Dh),Rr("CodeGroupItem")||e.component("CodeGroupItem",Hh);const n=t.options.scrollBehavior;t.options.scrollBehavior=async(...r)=>(await Oa().wait(),n(...r))},setup(){bh(),Ah()},layouts:{Layout:Gg,NotFound:Zg}}),tv=Object.freeze(Object.defineProperty({__proto__:null,default:ev},Symbol.toStringTag,{value:"Module"})),nv=e=>{const t=bt("keydown",n=>{const r=n.key==="k"&&(n.ctrlKey||n.metaKey);!(n.key==="/")&&!r||(n.preventDefault(),e(),t())})};function rv(e,t,n){var r,o,s;n===void 0&&(n={});var i=(r=n.isImmediate)!=null&&r,l=(o=n.callback)!=null&&o,a=n.maxWait,f=Date.now(),u=[];function c(){if(a!==void 0){var m=Date.now()-f;if(m+t>=a)return a-m}return t}var p=function(){var m=[].slice.call(arguments),v=this;return new Promise(function(y,C){var T=i&&s===void 0;if(s!==void 0&&clearTimeout(s),s=setTimeout(function(){if(s=void 0,f=Date.now(),!i){var g=e.apply(v,m);l&&l(g),u.forEach(function(b){return(0,b.resolve)(g)}),u=[]}},c()),T){var S=e.apply(v,m);return l&&l(S),y(S)}u.push({resolve:y,reject:C})})};return p.cancel=function(m){s!==void 0&&clearTimeout(s),u.forEach(function(v){return(0,v.reject)(m)}),u=[]},p}const ov=e=>e.button===1||e.altKey||e.ctrlKey||e.metaKey||e.shiftKey,sv=()=>{const e=qt();return{transformItems:t=>t.map(n=>({...n,url:`/docs/${ds(Mf(n.url,"/docs/"))}`})),hitComponent:({hit:t,children:n})=>({type:"a",ref:void 0,constructor:void 0,key:void 0,props:{href:t.url,onClick:r=>{ov(r)||(r.preventDefault(),e.push(t.url.replace("/docs/","/")))},children:n},__v:null}),navigator:{navigate:({itemUrl:t})=>{e.push(t.replace("/docs/","/"))}},transformSearchClient:t=>{const n=rv(t.search,500);return{...t,search:async(...r)=>n(...r)}}}};var iv={appId:"2LT25GG3KX",apiKey:"389be16f732f82c611e1b0f22c031dff",indexName:"engine-needle"};const lv=iv,av=ge(lv),Fa=Symbol(""),cv=()=>{const e=Fe(Fa),t=dn();return H(()=>{var n;return{...e.value,...(n=e.value.locales)==null?void 0:n[t.value]}})},uv=e=>{e.provide(Fa,av)},fv=(e,t=[])=>[`lang:${e}`,...Array.isArray(t)?t:[t]],dv=({buttonText:e="Search",buttonAriaLabel:t=e}={})=>``,pv=16,za=()=>{if(document.querySelector(".DocSearch-Modal"))return;const e=new Event("keydown");e.key="k",e.metaKey=!0,window.dispatchEvent(e),setTimeout(za,pv)},hv=e=>{const t="algolia-preconnect";("requestIdleCallback"in window?window.requestIdleCallback:setTimeout)(()=>{if(document.head.querySelector(`#${t}`))return;const r=document.createElement("link");r.id=t,r.rel="preconnect",r.href=`https://${e}-dsn.algolia.net`,r.crossOrigin="",document.head.appendChild(r)})},mv=fe({name:"DocSearch",props:{containerId:{type:String,default:"docsearch-container"},options:{type:Object,default:()=>({})}},setup(e){const t=cv(),n=sv(),r=va(),o=dn(),s=ge(!1),i=ge(!1),l=H(()=>{const{locales:u={},...c}=e.options;return{...t.value,...c,...u[o.value]}}),a=async()=>{var c;const{default:u}=await O(async()=>{const{default:p}=await import("./index-DWGeGWcS.js");return{default:p}},[]);u({...n,...l.value,container:`#${e.containerId}`,searchParameters:{...l.value.searchParameters,facetFilters:fv(r.value,(c=l.value.searchParameters)==null?void 0:c.facetFilters)}}),s.value=!0},f=()=>{i.value||s.value||(i.value=!0,a(),za(),ze(o,a))};return nv(f),We(()=>{hv(l.value.appId)}),()=>{var u;return[Ve("div",{id:e.containerId,style:{display:s.value?"block":"none"}}),s.value?null:Ve("div",{onClick:f,innerHTML:dv((u=l.value.translations)==null?void 0:u.button)})]}}}),gv={enhance({app:e}){uv(e),e.component("SearchBox",mv)}},vv=Object.freeze(Object.defineProperty({__proto__:null,default:gv},Symbol.toStringTag,{value:"Module"})),_v={enhance:({app:e})=>{e.component("NoDownloadYet",Se(()=>O(()=>import("./NoDownloadYet-CimAPJue.js"),[]))),e.component("action",Se(()=>O(()=>import("./action-Dm_y7Sbx.js"),[]))),e.component("actiongroup",Se(()=>O(()=>import("./actiongroup-gFGdAuKO.js"),[]))),e.component("contribution-header",Se(()=>O(()=>import("./contribution-header-B7v_pWCC.js"),[]))),e.component("contribution-listentry",Se(()=>O(()=>import("./contribution-listentry-CYemCd1W.js"),[]))),e.component("contribution-preview",Se(()=>O(()=>import("./contribution-preview-BGt1xWap.js"),[]))),e.component("contributions-author",Se(()=>O(()=>import("./contributions-author-BSwyEtB9.js"),[]))),e.component("contributions-overview",Se(()=>O(()=>import("./contributions-overview-D_rfeOIs.js"),[]))),e.component("copyright",Se(()=>O(()=>import("./copyright-ClhS8G3R.js"),[]))),e.component("github-star",Se(()=>O(()=>import("./github-star-DNJWumWy.js"),[]))),e.component("metalink",Se(()=>O(()=>import("./metalink-RADuWAM2.js"),[]))),e.component("needle-button",Se(()=>O(()=>import("./needle-button-CkzDHAYk.js"),[]))),e.component("os-link",Se(()=>O(()=>import("./os-link-CAGZ994T.js"),[]))),e.component("quoteslides",Se(()=>O(()=>import("./quoteslides-Jbcw9khk.js"),[]))),e.component("removeserviceworker",Se(()=>O(()=>import("./removeserviceworker-CWQpv6MD.js"),[]))),e.component("sample",Se(()=>O(()=>import("./sample-rKQKOG12.js"),[]))),e.component("stackblitz",Se(()=>O(()=>import("./stackblitz-DA3DcIUI.js"),[]))),e.component("testimonial",Se(()=>O(()=>import("./testimonial-yd4jmUbJ.js"),[]))),e.component("tool-tile",Se(()=>O(()=>import("./tool-tile-DaqpZjM0.js"),[]))),e.component("tool-tiles",Se(()=>O(()=>import("./tool-tiles-BfEF3OW4.js"),[]))),e.component("video-embed",Se(()=>O(()=>import("./video-embed-Dnh8jbMt.js"),[])))}},bv=Object.freeze(Object.defineProperty({__proto__:null,default:_v},Symbol.toStringTag,{value:"Module"})),yv=e=>{if(window.dataLayer&&window.gtag)return;const t=document.createElement("script");t.src=`https://www.googletagmanager.com/gtag/js?id=${e.id}`,t.async=!0,document.head.appendChild(t),window.dataLayer=window.dataLayer??[],window.gtag=function(){window.dataLayer.push(arguments)},window.gtag("js",new Date),window.gtag("config",e.id)};var Ev={id:"G-V2Q445L3XQ",debug:!1};const wv=Ev,Sv=Yt({enhance(){yv(wv)}}),Pv=Object.freeze(Object.defineProperty({__proto__:null,default:Sv},Symbol.toStringTag,{value:"Module"})),xv=Object.freeze(Object.defineProperty({__proto__:null},Symbol.toStringTag,{value:"Module"})),Lv=Yt({enhance({app:e,router:t,siteData:n}){},setup(){},rootComponents:[]}),Cv=Object.freeze(Object.defineProperty({__proto__:null,default:Lv},Symbol.toStringTag,{value:"Module"})),kr=[Ap,Up,Wp,oh,uh,gh,tv,vv,bv,Pv,xv,Cv].map(e=>e.default).filter(Boolean),Tv=JSON.parse('{"base":"/docs/","lang":"en-US","title":"Needle Engine Documentation","description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets.","head":[["link",{"rel":"icon","href":"https://engine.needle.tools/docs/icons/favicon.ico"}],["link",{"rel":"manifest","href":"manifest.webmanifest"}],["meta",{"name":"theme-color","content":"#3eaf7c"}],["meta",{"property":"og:title","content":"Needle Engine Documentation"}],["meta",{"property":"og:type","content":"website"}],["meta",{"property":"og:url","content":"https://engine.needle.tools/docs"}],["meta",{"property":"twitter:card","content":"summary_large_image"}],["script",{"src":"https://unpkg.com/@stackblitz/sdk/bundles/sdk.umd.js"}],["script",{"src":"https://analytics.needle.tools/js/script.tagged-events.outbound-links.js","defer":"","data-domain":"docs.needle.tools"}]],"locales":{}}');var jn=fn(Tv),kv=wd,Av=()=>{const e=Kd({history:kv(oa("/docs/")),routes:[{name:"vuepress-route",path:"/:catchAll(.*)",components:{}}],scrollBehavior:(t,n,r)=>r||(t.hash?{el:t.hash}:{top:0})});return e.beforeResolve(async(t,n)=>{if(t.path!==n.path||n===xt){const r=nr(t.fullPath);if(r.path!==t.fullPath)return r.path;const o=await r.loader();t.meta={...r.meta,_pageChunk:o}}else t.path===n.path&&(t.meta=n.meta)}),e},Ov=e=>{e.component("ClientOnly",_s),e.component("Content",bs),e.component("RouteLink",io)},Rv=(e,t,n)=>{const r=H(()=>t.currentRoute.value.path),o=Oc((C,T)=>({get(){return C(),t.currentRoute.value.meta._pageChunk},set(S){t.currentRoute.value.meta._pageChunk=S,T()}})),s=H(()=>Zt.resolveLayouts(n)),i=H(()=>Zt.resolveRouteLocale(jn.value.locales,r.value)),l=H(()=>Zt.resolveSiteLocaleData(jn.value,i.value)),a=H(()=>o.value.comp),f=H(()=>o.value.data),u=H(()=>f.value.frontmatter),c=H(()=>Zt.resolvePageHeadTitle(f.value,l.value)),p=H(()=>Zt.resolvePageHead(c.value,u.value,l.value)),m=H(()=>Zt.resolvePageLang(f.value,l.value)),v=H(()=>Zt.resolvePageLayout(f.value,s.value)),y={layouts:s,pageData:f,pageComponent:a,pageFrontmatter:u,pageHead:p,pageHeadTitle:c,pageLang:m,pageLayout:v,redirects:zo,routeLocale:i,routePath:r,routes:xn,siteData:jn,siteLocaleData:l};return e.provide(gs,y),Object.defineProperties(e.config.globalProperties,{$frontmatter:{get:()=>u.value},$head:{get:()=>p.value},$headTitle:{get:()=>c.value},$lang:{get:()=>m.value},$page:{get:()=>f.value},$routeLocale:{get:()=>i.value},$site:{get:()=>jn.value},$siteLocale:{get:()=>l.value},$withBase:{get:()=>ys}}),y},Iv=()=>{const e=Yd(),t=va();let n=[];const r=()=>{e.value.forEach(i=>{const l=Dv(i);l&&n.push(l)})},o=()=>{const i=[];return e.value.forEach(l=>{const a=Mv(l);a&&i.push(a)}),i},s=()=>{document.documentElement.lang=t.value;const i=o();n.forEach((l,a)=>{const f=i.findIndex(u=>l.isEqualNode(u));f===-1?(l.remove(),delete n[a]):i.splice(f,1)}),i.forEach(l=>document.head.appendChild(l)),n=[...n.filter(l=>!!l),...i]};an(Xd,s),We(()=>{r(),ze(e,s,{immediate:!1})})},Dv=([e,t,n=""])=>{const r=Object.entries(t).map(([l,a])=>ut(a)?`[${l}=${JSON.stringify(a)}]`:a===!0?`[${l}]`:"").join(""),o=`head > ${e}${r}`;return Array.from(document.querySelectorAll(o)).find(l=>l.innerText===n)||null},Mv=([e,t,n])=>{if(!ut(e))return null;const r=document.createElement(e);return ps(t)&&Object.entries(t).forEach(([o,s])=>{ut(s)?r.setAttribute(o,s):s===!0&&r.setAttribute(o,"")}),ut(n)&&r.appendChild(document.createTextNode(n)),r},Vv=Cf,Hv=async()=>{var n;const e=Vv({name:"Vuepress",setup(){var s;Iv();for(const i of kr)(s=i.setup)==null||s.call(i);const r=kr.flatMap(({rootComponents:i=[]})=>i.map(l=>Ve(l))),o=Jd();return()=>[Ve(o.value),r]}}),t=Av();Ov(e),Rv(e,t,kr);for(const r of kr)await((n=r.enhance)==null?void 0:n.call(r,{app:e,router:t,siteData:jn}));return e.use(t),{app:e,router:t}};Hv().then(({app:e,router:t})=>{t.isReady().then(()=>{e.mount("#app")})});export{me as F,we as _,re as a,se as b,ee as c,Hv as createVueApp,zt as d,Nu as e,xe as f,Ae as g,fe as h,Wt as i,Ve as j,ue as k,O as l,Ce as m,Qe as n,K as o,Yt as p,We as q,as as r,Le as t,$v as u,ke as w}; diff --git a/assets/ar-move-scale-rotate-controls-for-needle-on-mobile.html-CUtGjdNc.js b/assets/ar-move-scale-rotate-controls-for-needle-on-mobile.html-CUtGjdNc.js new file mode 100644 index 000000000..389c94e72 --- /dev/null +++ b/assets/ar-move-scale-rotate-controls-for-needle-on-mobile.html-CUtGjdNc.js @@ -0,0 +1 @@ +import{_ as n,r,o as a,c as i,a as t,b as s}from"./app-CRZRGfEE.js";const l={};function d(u,e){const o=r("contribution-header");return a(),i("div",null,[e[0]||(e[0]=t("p",null,[t("a",{href:"/docs/community/contributions"},"Overview")],-1)),s(o,{url:"https://github.com/ROBYER1",author:"ROBYER1",page:"/docs/community/contributions/robyer1",profileImage:"https://avatars.githubusercontent.com/u/10745594?s=100&u=daf2c8b5dad729e556ae2a01c721672b24bc108a&v=4",githubUrl:"https://github.com/needle-tools/needle-engine-support/discussions/174",title:"AR Move/Scale/Rotate Controls for Needle on Mobile",gradient:"True"}),e[1]||(e[1]=t("p",null,"This is live for preview over at https://needle-ar.glitch.me/",-1)),e[2]||(e[2]=t("p",null,"I will share a github repository if others are interested in collaborating on this, so far I have just sorted functionality for spawning a product model and a floor plane that is large to move it around on. Scale and Rotate work with two finger touches.",-1)),e[3]||(e[3]=t("p",null,"I am hoping to figure out how to show and raycast against AR detected planes over here which will remove the need for a large floor plane to raycast against โ Unknown",-1)),e[4]||(e[4]=t("p",null,"Public Github Repository: https://github.com/ROBYER1/Needle-AR-Demo",-1))])}const m=n(l,[["render",d],["__file","ar-move-scale-rotate-controls-for-needle-on-mobile.html.vue"]]),c=JSON.parse('{"path":"/community/contributions/robyer1/ar-move-scale-rotate-controls-for-needle-on-mobile","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/robyer1: ar move scale rotate controls for needle on mobile.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{m as comp,c as data}; diff --git a/assets/backlog-mermaid.html-Baq9DOuh.js b/assets/backlog-mermaid.html-Baq9DOuh.js new file mode 100644 index 000000000..3b8d337d6 --- /dev/null +++ b/assets/backlog-mermaid.html-Baq9DOuh.js @@ -0,0 +1,14 @@ +import{_ as s,o as a,c as t,e as i}from"./app-CRZRGfEE.js";const n={};function l(r,e){return a(),t("div",null,e[0]||(e[0]=[i(`
flowchart LR
+  Editor([<b>C# components</b><br/>on GameObjects]) --> gltf[<b>JSON data</b><br/>as glTF Extension] --> Runtime([<b>JavaScript components</b><br/>on Object3D])
+  class Editor,gltf,Runtime bg;
flowchart LR
+    Editor([Unity Editor]) --> EditorExt([Components + Tools])
+    EditorExt -- export data --> glTF([glTF + Extensions])
+    glTF --> Bundler([Bundler - vite])
+    Runtime([Needle Runtime]) --> Bundler
+    Three([Three.js]) --> Bundler
+    YourWebsite([Classic web files - HTML, CSS, JS]) --> Bundler
+    Bundler -- outputs --> DevPage([web app - dev])
+    Bundler -- outputs --> DeploymentPage([web app - deploy])
+    glTF -- compressed with --> gltfTransform([glTF-transform]) --> DeploymentPage
+    class EditorExt,glTF,Runtime ndl;
+    class Editor,Three,Bundler,Page,gltfTransform,DeploymentPage,DevPage,YourWebsite ext;
`,2)]))}const d=s(n,[["render",l],["__file","backlog-mermaid.html.vue"]]),o=JSON.parse('{"path":"/backlog-mermaid.html","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/backlog mermaid.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{"updatedTime":1666603563000},"filePathRelative":"_backlog-mermaid.md"}');export{d as comp,o as data}; diff --git a/assets/backlog.html-aIMMEHhy.js b/assets/backlog.html-aIMMEHhy.js new file mode 100644 index 000000000..c47525cfe --- /dev/null +++ b/assets/backlog.html-aIMMEHhy.js @@ -0,0 +1 @@ +import{_ as t,o as n,c as o,e as i}from"./app-CRZRGfEE.js";const a={};function r(s,e){return n(),o("div",null,e[0]||(e[0]=[i('

Documentation Backlog

This section contains pieces of information that are important, but need to be sorted into their correct categories.

  • Unity 2020.3.8f1+ or 2022.1+
  • Render Pipeline: Universal
  • Color Space: Linear
  • Non-Directional Lightmaps
  • Lightmap Encoding: Normal Quality

Supported Unity configurations

  • Unity 2020.3+ | Unity 2021.3+ | Unity 2022.1+
  • Render Pipeline: Universal | Built-In1
  • Color Space: Linear

1: no custom shader support

Source Control

Generated Projects can either be added to source control or kept dynamic. Adding them to source control unlocks being able to adjust HTML, CSS, etc very flexible.
To generate dynamic projects, change their path to ../Library/MyScene. They will be regenerated if needed.

Please follow the instructions in the Authentication section if this is your first time accessing packages by needle on this machine.

Licensing Setup

Note: This section is deprecated. Needle Engine is currently on Open Beta, and there's no need to authenticate against our registry at this point.

Authentication

Make sure you have a Needle Engine and Exporter license, otherwise the following steps will fail (you'll not be able to get authenticated package access).

Needs to be setup once per machine.

  1. Clone this repository and open starter/Authenticate with Unity 2020.3.x
  2. Open https://packages.needle.tools โ‡ก in your browser and login (top right corner) with your github account.
  3. Return to packages.needle.tools โ‡ก and click the i icon in the top right corner opening the Registry Info window.
  4. Copy the line containing _authToken (see the video below)
  5. Focus Unity - a notification window should open that the information has been added successfully from your clipboard.
  6. Click save and close Unity. You should now have access rights to the needle package registry.
',16)]))}const c=t(a,[["render",r],["__file","backlog.html.vue"]]),d=JSON.parse('{"path":"/backlog.html","title":"Documentation Backlog","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/backlog.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[{"level":2,"title":"Recommended Unity configuration","slug":"recommended-unity-configuration","link":"#recommended-unity-configuration","children":[]},{"level":2,"title":"Supported Unity configurations","slug":"supported-unity-configurations","link":"#supported-unity-configurations","children":[]},{"level":2,"title":"Source Control","slug":"source-control","link":"#source-control","children":[]},{"level":2,"title":"Authentication","slug":"authentication","link":"#authentication","children":[]}],"git":{"updatedTime":1669763662000},"filePathRelative":"_backlog.md"}');export{c as comp,d as data}; diff --git a/assets/buttons.esm-CUWjhgaJ.js b/assets/buttons.esm-CUWjhgaJ.js new file mode 100644 index 000000000..52baca35a --- /dev/null +++ b/assets/buttons.esm-CUWjhgaJ.js @@ -0,0 +1,5 @@ +/*! + * github-buttons v2.29.0 + * (c) 2024 ใชใคใ + * @license BSD-2-Clause + */var C=window.document,p=window.Math,k=window.HTMLElement,b=window.XMLHttpRequest,F=function(e,t){for(var r=0,o=e.length;r'}}},download:{heights:{16:{width:16,path:''}}},eye:{heights:{16:{width:16,path:''}}},heart:{heights:{16:{width:16,path:''}}},"issue-opened":{heights:{16:{width:16,path:''}}},"mark-github":{heights:{16:{width:16,path:''}}},package:{heights:{16:{width:16,path:''}}},play:{heights:{16:{width:16,path:''}}},"repo-forked":{heights:{16:{width:16,path:''}}},"repo-template":{heights:{16:{width:16,path:''}}},star:{heights:{16:{width:16,path:''}}}},oe=function(e,t){e=Z(e).replace(/^octicon-/,""),m(x,e)||(e="mark-github");var r=t>=24&&24 in x[e].heights?24:16,o=x[e].heights[r];return'"},y={},re=function(e,t){var r=y[e]||(y[e]=[]);if(!(r.push(t)>1)){var o=V(function(){for(delete y[e];t=r.shift();)t.apply(null,arguments)});if(S){var a=new b;f(a,"abort",o),f(a,"error",o),f(a,"load",function(){var s;try{s=JSON.parse(this.responseText)}catch(d){o(d);return}o(this.status!==200,s)}),a.open("GET",e),a.send()}else{var n=this||window;n._=function(s){n._=null,o(s.meta.status!==200,s.data)};var c=A(n.document)("script",{async:!0,src:e+(e.indexOf("?")!==-1?"&":"?")+"callback=_"}),l=function(){n._&&n._({meta:{}})};f(c,"load",l),f(c,"error",l),$(c,/de|m/,l),n.document.getElementsByTagName("head")[0].appendChild(c)}}},T=function(e,t,r){var o=A(e.ownerDocument),a=e.appendChild(o("style",{type:"text/css"})),n=J+te(t["data-color-scheme"]);a.styleSheet?a.styleSheet.cssText=n:a.appendChild(e.ownerDocument.createTextNode(n));var c=Z(t["data-size"])==="large",l=o("a",{className:"btn",href:t.href,rel:"noopener",target:"_blank",title:t.title||void 0,"aria-label":t["aria-label"]||void 0,innerHTML:oe(t["data-icon"],c?16:14)+" "},[o("span",{},[t["data-text"]||""])]),s=e.appendChild(o("div",{className:"widget"+(c?" widget-lg":"")},[l])),d=l.hostname.replace(/\.$/,"");if(("."+d).substring(d.length-u.length)!=="."+u){l.removeAttribute("href"),r(s);return}var i=(" /"+l.pathname).split(/\/+/);if(((d===u||d==="gist."+u)&&i[3]==="archive"||d===u&&i[3]==="releases"&&(i[4]==="download"||i[4]==="latest"&&i[5]==="download")||d==="codeload."+u)&&(l.target="_top"),Z(t["data-show-count"])!=="true"||d!==u||i[1]==="marketplace"||i[1]==="sponsors"||i[1]==="orgs"||i[1]==="users"||i[1]==="-"){r(s);return}var v,h;if(!i[2]&&i[1])h="followers",v="?tab=followers";else if(!i[3]&&i[2])h="stargazers_count",v="/stargazers";else if(!i[4]&&i[3]==="subscription")h="subscribers_count",v="/watchers";else if(!i[4]&&i[3]==="fork")h="forks_count",v="/forks";else if(i[3]==="issues")h="open_issues_count",v="/issues";else{r(s);return}var D=i[2]?"/repos/"+i[1]+"/"+i[2]:"/users/"+i[1];re.call(this,P+D,function(B,L){if(!B){var w=L[h];s.appendChild(o("a",{className:"social-count",href:L.html_url+v,rel:"noopener",target:"_blank","aria-label":w+" "+h.replace(/_count$/,"").replace("_"," ").slice(0,w<2?-1:void 0)+" on GitHub"},[(""+w).replace(/\B(?=(\d{3})+(?!\d))/g,",")]))}r(s)})},M=window.devicePixelRatio||1,z=function(e){return(M>1?p.ceil(p.round(e*M)/M*2)/2:p.ceil(e))||0},ae=function(e){var t=e.offsetWidth,r=e.offsetHeight;if(e.getBoundingClientRect){var o=e.getBoundingClientRect();t=p.max(t,z(o.width)),r=p.max(r,z(o.height))}return[t,r]},H=function(e,t){e.style.width=t[0]+"px",e.style.height=t[1]+"px"},ne=function(e,t){if(!(e==null||t==null))if(e.getAttribute&&(e=q(e)),R){var r=_("span");T(r.attachShadow({mode:"closed"}),e,function(){t(r)})}else{var o=_("iframe",{src:"javascript:0",title:e.title||void 0,allowtransparency:!0,scrolling:"no",frameBorder:0});H(o,[0,0]),o.style.border="none";var a=function(){var n=o.contentWindow,c;try{c=n.document.body}catch{C.body.appendChild(o.parentNode.removeChild(o));return}E(o,"load",a),T.call(n,c,e,function(l){var s=ae(l);o.parentNode.removeChild(o),I(o,"load",function(){H(o,s)}),o.src=N+"#"+(o.name=W(e)),t(o)})};f(o,"load",a),C.body.appendChild(o)}};export{ne as render}; diff --git a/assets/calculate-pointer-world-position.html-BBtMcQ13.js b/assets/calculate-pointer-world-position.html-BBtMcQ13.js new file mode 100644 index 000000000..cf0f85e56 --- /dev/null +++ b/assets/calculate-pointer-world-position.html-BBtMcQ13.js @@ -0,0 +1,37 @@ +import{_ as t,r as n,o as h,c as l,a as s,b as k,e}from"./app-CRZRGfEE.js";const p={};function r(d,i){const a=n("contribution-header");return h(),l("div",null,[i[0]||(i[0]=s("p",null,[s("a",{href:"/docs/community/contributions"},"Overview")],-1)),k(a,{url:"https://github.com/kipash",author:"kipash",page:"/docs/community/contributions/kipash",profileImage:"https://avatars.githubusercontent.com/u/30328735?s=100&u=f28398f4575da1835d1c710d14763c69418cd0fa&v=4",githubUrl:"https://github.com/needle-tools/needle-engine-support/discussions/165",title:"Calculate pointer world position",gradient:"True"}),i[1]||(i[1]=e(`

https://github.com/needle-tools/needle-engine-support/assets/30328735/92404e43-9d45-4ee2-a018-fb00412b6bd5

import { Behaviour, serializable, setWorldPosition } from "@needle-tools/engine";
+import { Object3D, Vector3 } from "three";
+
+const vector1 = new Vector3();
+const vector2 = new Vector3();
+
+export class PointerFollower extends Behaviour {
+
+    @serializable(Object3D)
+    target?: Object3D;
+
+    @serializable()
+    offset: number = 10;
+
+    update(): void {
+        const cam = this.context.mainCamera;
+        const input = this.context.input;
+
+        if(!this.target || !cam)
+            return;
+
+        // get relative mouse position, in range -1 to 1
+        const mouse = input.mousePositionRC;
+
+        // get world position of mouse on the near plane
+        vector1.set(mouse.x, mouse.y, -1).unproject(cam!);
+
+        // caulculate direction from camera to world mouse
+        vector2.copy(vector1).sub(cam.position).normalize();
+
+        // offset it to the wanted distance
+        vector1.addScaledVector(vector2, this.offset);
+
+        // apply the result
+        setWorldPosition(this.target, vector1);
+    }
+}
`,2))])}const g=t(p,[["render",r],["__file","calculate-pointer-world-position.html.vue"]]),C=JSON.parse('{"path":"/community/contributions/kipash/calculate-pointer-world-position","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/kipash: calculate pointer world position.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{g as comp,C as data}; diff --git a/assets/camera-video-background.html-BLeFh9kF.js b/assets/camera-video-background.html-BLeFh9kF.js new file mode 100644 index 000000000..699b1a2f8 --- /dev/null +++ b/assets/camera-video-background.html-BLeFh9kF.js @@ -0,0 +1,29 @@ +import{_ as n,r as t,o as h,c as l,a as s,b as e,e as k}from"./app-CRZRGfEE.js";const p={};function r(d,i){const a=t("contribution-header");return h(),l("div",null,[i[0]||(i[0]=s("p",null,[s("a",{href:"/docs/community/contributions"},"Overview")],-1)),e(a,{url:"https://github.com/marwie",author:"marwie",page:"/docs/community/contributions/marwie",profileImage:"https://avatars.githubusercontent.com/u/5083203?s=100&v=4",githubUrl:"https://github.com/needle-tools/needle-engine-support/discussions/166",title:"Camera Video Background",gradient:"True"}),i[1]||(i[1]=k(`

Put it anywhere in your scene to render a camera video behind your 3D scene Live demo

import { Behaviour, ClearFlags, RGBAColor } from "@needle-tools/engine";
+
+export class VideoBackground extends Behaviour {
+
+    async awake() {
+        // create video element and put it inside the <needle-engine> component
+        const video = document.createElement("video");
+        video.style.cssText = \`
+            position: fixed;
+            min-width: 100%;
+            min-height: 100%;
+            z-index: -1;
+        \`
+        this.context.domElement.shadowRoot!.appendChild(video);
+
+        // get webcam input
+        const input = await navigator.mediaDevices.getUserMedia({ video: true })
+        if (!input) return;
+        video.srcObject = input;
+        video.play();
+
+        // make sure the camera background is transparent
+        const camera = this.context.mainCameraComponent;
+        if (camera) {
+            camera.clearFlags = ClearFlags.SolidColor;
+            camera.backgroundColor = new RGBAColor(125, 125, 125, 0);
+        }
+    }
+}
`,2))])}const g=n(p,[["render",r],["__file","camera-video-background.html.vue"]]),C=JSON.parse('{"path":"/community/contributions/marwie/camera-video-background","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/marwie: camera video background.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{g as comp,C as data}; diff --git a/assets/code-contribution-example.html-BnLNxDrY.js b/assets/code-contribution-example.html-BnLNxDrY.js new file mode 100644 index 000000000..a622909f5 --- /dev/null +++ b/assets/code-contribution-example.html-BnLNxDrY.js @@ -0,0 +1,16 @@ +import{_ as a,r as e,o as n,c as l,a as s,b as h,e as p}from"./app-CRZRGfEE.js";const o={};function k(r,i){const t=e("contribution-header");return n(),l("div",null,[i[0]||(i[0]=s("p",null,[s("a",{href:"/docs/community/contributions"},"Overview")],-1)),h(t,{url:"https://github.com/marwie",author:"marwie",page:"/docs/community/contributions/marwie",profileImage:"https://avatars.githubusercontent.com/u/5083203?s=100&v=4",githubUrl:"https://github.com/needle-tools/needle-engine-support/discussions/146",title:"Code Contribution Example",gradient:"True"}),i[1]||(i[1]=p(`

This is mostly a basic example on how to contribute. It will then be added on our documentation contributions page: https://engine.needle.tools/docs/community/contributions

Please include at least one code snippet, for example like this:

import { Behaviour, serializable } from "@needle-tools/engine"
+import { Object3D } from "three"
+
+export class MyComponent extends Behaviour {
+
+    @serializable(Object3D)
+    myObjectReference?: Object3D;
+
+    start() {
+        console.log("Hello world", this);
+    }
+
+    update() {
+        // called every frame
+    }
+}
`,3))])}const c=a(o,[["render",k],["__file","code-contribution-example.html.vue"]]),g=JSON.parse('{"path":"/community/contributions/marwie/code-contribution-example","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/marwie: code contribution example.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{c as comp,g as data}; diff --git a/assets/component-compiler.html-DQMaNo6k.js b/assets/component-compiler.html-DQMaNo6k.js new file mode 100644 index 000000000..ac968b543 --- /dev/null +++ b/assets/component-compiler.html-DQMaNo6k.js @@ -0,0 +1,98 @@ +import{_ as r,r as n,o as p,c as o,e as h,b as a,w as l,a as i,d as s}from"./app-CRZRGfEE.js";const d={};function c(y,t){const e=n("CodeGroupItem"),k=n("CodeGroup");return p(),o("div",null,[t[3]||(t[3]=h(`

Automatically generating Editor components

When working in Unity or Blender then you will notice that when you create a new Needle Engine component in Typescript or Javascript it will automatically generate a Unity C# stub component OR a Blender panel for you.

This is thanks to the magic of the Needle component compiler that runs behind the scenes in an editor environment and watches changes to your script files. When it notices that you created a new Needle Engine component it will then generate the correct Unity component or Blender panel including public variables or properties that you can then set or link from within the Editor.

Controlling component generation

You can use the following comments in your typescript code to control C# code generation behavior:

AttributeResult
// @generate-componentForce generation of next class
// @dont-generate-componentDisable generation of next class, this is useful in cases where you already have an existing C# script in your project
// @serializeFieldDecorate generated field with [SerializeField]
// @type UnityEngine.CameraSpecify generated C# field type
// @nonSerializedSkip generating the next field or method

Examples

Force the component compiler to generate a C# AudioClip field named myAudioClip

import { Behaviour, serializable } from "@needle-tools/engine";
+
+export class MyComponent extends Behaviour {
+	//@type UnityEngine.AudioClip
+	@serializable()
+	myAudioClip?: string;
+}

Force the component compiler to derive from a specific subclass

import { Behaviour } from "@needle-tools/engine";
+export class MyCustomBaseClass extends Behaviour { /* ... */ }
+// ---cut-before---
+//@type MyNamespace.MyCustomBaseClass
+export class MyComponent extends MyCustomBaseClass {
+}

Component Compiler in Unity

If you want to add scripts inside the src/scripts folder in your project then you need to have a Component Generator on the GameObject with your ExportInfo component.
Now when adding new components in your/threejs/project/src/scriptsit will automatically generate Unity scripts in Assets/Needle/Components.codegen.
If you want to add scripts to any NpmDef file you can just create them - each NpmDef automatically watches script changes and handles component generation, so you don't need any additional component in your scene.

For C# fields to be correctly generated it is currently important that you explictly declare a Typescript type. For example myField : number = 5

You can switch between Typescript input and generated C# stub components using the tabs below

`,15)),a(k,null,{default:l(()=>[a(e,{title:"Typescript"},{default:l(()=>t[0]||(t[0]=[i("div",{class:"language-ts","data-highlighter":"shiki","data-ext":"ts","data-title":"ts",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[i("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[i("code",null,[i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," AssetReference"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Behaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," serializable "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "@needle-tools/engine"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Object3D "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "three"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"export"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," class"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," MyCustomComponent"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," extends"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Behaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," @serializable"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"()")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," myFloatValue"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," number"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," ="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 42"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," @serializable"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"("),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Object3D"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," myOtherObject"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?:"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Object3D"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," @serializable"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"("),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"AssetReference"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," prefabs"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," AssetReference[] "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," []"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," start"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"sayHello"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," sayHello"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," console"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"log"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"Hello World"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}")])])])],-1)])),_:1}),a(e,{title:"Generated C#"},{default:l(()=>t[1]||(t[1]=[i("div",{class:"language-csharp","data-highlighter":"shiki","data-ext":"csharp","data-title":"csharp",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[i("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[i("code",null,[i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"// NEEDLE_CODEGEN_START")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"// auto generated code - do not edit directly")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"#"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"pragma"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," warning"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," disable")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"namespace"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Needle"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"Typescript"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"GeneratedComponents")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," public"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," partial"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," class"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," MyCustomComponent"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," :"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," UnityEngine"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"MonoBehaviour")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," public"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," float"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," @myFloatValue "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 42f"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," public"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," UnityEngine"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"Transform"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," @myOtherObject"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," public"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," UnityEngine"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"Transform"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"[]"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," @prefabs "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," new"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," UnityEngine"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"Transform"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"[]{"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," };")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," public"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," void"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," start"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"(){}")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," public"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," void"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," update"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"(){}")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"// NEEDLE_CODEGEN_END")])])])],-1)])),_:1}),a(e,{title:"Extending Generated C#"},{default:l(()=>t[2]||(t[2]=[i("div",{class:"language-csharp","data-highlighter":"shiki","data-ext":"csharp","data-title":"csharp",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[i("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[i("code",null,[i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"using"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," UnityEditor"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"// you can add code above or below the NEEDLE_CODEGEN_ blocks")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"// NEEDLE_CODEGEN_START")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"// auto generated code - do not edit directly")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"#"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"pragma"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," warning"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," disable")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"namespace"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Needle"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"Typescript"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"GeneratedComponents")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," public"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," partial"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," class"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," MyCustomComponent"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," :"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," UnityEngine"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"MonoBehaviour")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," public"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," float"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," @myFloatValue "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 42f"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," public"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," UnityEngine"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"Transform"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," @myOtherObject"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," public"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," UnityEngine"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"Transform"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"[]"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," @prefabs "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," new"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," UnityEngine"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"Transform"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"[]{"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," };")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," public"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," void"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," start"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"(){}")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," public"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," void"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," update"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"(){}")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"// NEEDLE_CODEGEN_END")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"namespace"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Needle"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"Typescript"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"GeneratedComponents")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," // This is how you extend the generated component (namespace and class name must match!)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," public"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," partial"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," class"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," MyCustomComponent"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," :"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," UnityEngine"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"MonoBehaviour")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," public"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," void"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," MyAdditionalMethod"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," void"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," OnValidate"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," myFloatValue "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 42"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," // of course you can also add custom editors")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," ["),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"CustomEditor"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"("),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"typeof"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"("),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"MyCustomComponent"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"))]")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," public"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," class"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," MyCustomComponentEditor"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," :"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Editor")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," public"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," override"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," void"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," OnInspectorGUI"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," EditorGUILayout"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"HelpBox"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"This is my sample component"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," MessageType"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"None"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},");")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," base"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"OnInspectorGUI"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"();")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}")])])])],-1)])),_:1})]),_:1}),t[4]||(t[4]=h('

Extending generated components

Component C# classes are generated with the partial flag so that it is easy to extend them with functionality. This is helpful to draw gizmos, add context menus or add additional fields or methods that are not part of a built-in component.

Member Casing

Exported members will start with a lowercase letter. For example if your C# member is named MyString it will be assigned to myString.

',3))])}const C=r(d,[["render",c],["__file","component-compiler.html.vue"]]),E=JSON.parse('{"path":"/component-compiler.html","title":"Automatic Component Generation","lang":"en-US","frontmatter":{"title":"Automatic Component Generation","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/automatic component generation.png"}],["meta",{"name":"og:description","content":"---\\nWhen working in Unity or Blender then you will notice that when you create a new Needle Engine component in Typescript or Javascript it will automatically generate a Unity Cstub component OR a Blender panel for you.\\nThis is thanks to the magic of the Needle component compiler that runs behind the scenes in an editor environment and watches changes to your script files. When it notices that you created a new Needle Engine component it will then generate the correct Unity component or Blender panel including public variables or properties that you can then set or link from within the Editor.\\nYou can use the following comments in your typescript code to control Ccode generation behavior:"}]],"description":"---\\nWhen working in Unity or Blender then you will notice that when you create a new Needle Engine component in Typescript or Javascript it will automatically generate a Unity Cstub component OR a Blender panel for you.\\nThis is thanks to the magic of the Needle component compiler that runs behind the scenes in an editor environment and watches changes to your script files. When it notices that you created a new Needle Engine component it will then generate the correct Unity component or Blender panel including public variables or properties that you can then set or link from within the Editor.\\nYou can use the following comments in your typescript code to control Ccode generation behavior:"},"headers":[{"level":3,"title":"Automatically generating Editor components","slug":"automatically-generating-editor-components","link":"#automatically-generating-editor-components","children":[]},{"level":3,"title":"Controlling component generation","slug":"controlling-component-generation","link":"#controlling-component-generation","children":[]},{"level":3,"title":"Component Compiler in Unity","slug":"component-compiler-in-unity","link":"#component-compiler-in-unity","children":[]},{"level":3,"title":"Extending generated components","slug":"extending-generated-components","link":"#extending-generated-components","children":[]}],"git":{"updatedTime":1726514637000},"filePathRelative":"component-compiler.md"}');export{C as comp,E as data}; diff --git a/assets/component-reference.html-zo-jLPyy.js b/assets/component-reference.html-zo-jLPyy.js new file mode 100644 index 000000000..589c40cf3 --- /dev/null +++ b/assets/component-reference.html-zo-jLPyy.js @@ -0,0 +1 @@ +import{_ as i,r as l,o as s,c,a as t,d as o,b as r,w as n,e as a}from"./app-CRZRGfEE.js";const h={};function p(u,e){const d=l("RouteLink");return s(),c("div",null,[e[16]||(e[16]=t("h1",{id:"needle-core-components",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#needle-core-components"},[t("span",null,"Needle Core Components")])],-1)),e[17]||(e[17]=t("p",null,"Here is a overview of some of the components that we provide. Many of them map to components and functionality in Unity, Blender or other integrations.",-1)),e[18]||(e[18]=t("p",null,[o("For a complete list please have a look at our "),t("a",{href:"https://engine.needle.tools/docs/api/latest",target:"_blank",rel:"noopener noreferrer"},"API docs"),o(".")],-1)),e[19]||(e[19]=t("p",null,"You can always add your own components or add wrappers for Unity components we haven't provided yet.",-1)),t("p",null,[e[1]||(e[1]=o("Learn more in the ")),r(d,{to:"/scripting.html"},{default:n(()=>e[0]||(e[0]=[o("Scripting")])),_:1}),e[2]||(e[2]=o(" section of our docs."))]),e[20]||(e[20]=a('

Audio

NameDescription
AudioListener
AudioSourceUse to play audio

Animation

NameDescription
Animator with AnimatorControllerExport with animation state machine, conditions, transitions
AnimationMost basic animation component. Only first clip is exported
PlayableDirector with TimelineAssetExport powerful sequences to control animation, audio, state and more

Rendering

NameDescription
Camera
LightDirectionalLight, PointLight, Spotlight. Note that you can use it to bake light (e.g. Rectangular Light shapes) as well
XRFlagControl when objects will be visible. E.g. only enable object when in AR
DeviceFlagControl on which device objects will be visible
LODGroup
ParticleSystemExperimental and currently not fully supported
VideoPlayerPlayback videos from url or referenced video file (will be copied to output on export). The VideoPlayer also supports streaming from MediaStream objects or M3U8 livestream URLs
MeshRendererUsed to handle rendering of objects including lightmapping and instancing
SkinnedMeshRendererSee MeshRenderer
SpriteRendererUsed to render Sprites and Spriteanimations
Volume with PostProcessing assetSee table below

Postprocessing

Postprocessing effects use the pmndrs postprocessing library under the hood. This means you can also easily add your own custom effects and get an automatically optimized postprocessing pass.

  • Unity only: Note that Postprocessing effects using a Volume in Unity is only supported with URP
Effect Name
Antialiasingextra Unity Component
Bloomvia Volume asset
Chromatic Aberrationvia Volume asset
Color Adjustments / Color Correctionvia Volume asset
Depth Of Fieldvia Volume asset
Vignettevia Volume asset
ToneMappingEffectvia Volume asset or separate component
Pixelation
Screenspace Ambient Occlusion N8
Screenspace Ambient Occlusion
Tilt Shift Effect
SharpeningEffect
Your custom effectSee example on stackblitz

Networking

NameDescription
SyncedRoomMain networking component. Put in your scene to enable networking
NetworkingUsed to setup backend server for networking.
SyncedTransformAutomatically network object transformation
SyncedCameraAutomatically network camera position and view to other users in room. You can define how the camera is being rendered by referencing an object
WebXRSyncNetworks WebXR avatars (AR and VR)
VoipEnables voice-chat
ScreensharingEnables screen-sharing capabilities

Interaction

NameDescription
EventSystemHandles raising pointer events and UI events on objects in the scene
ObjectRaycaterRequired for DragControls and Duplicatable
GraphicsRaycasterSame as ObjectRaycaster but for UI elements
DragControlsAllows objects to be dragged in the scene. Requires raycaster in parent hierarchy, e.g. ObjectRaycaster
DuplicatableCan duplicate assigned objects by drag. Requires DragControls
InteractableBasic component to mark an object to be interactable.
OrbitControlsAdd to camera to add camera orbit control functionality
SmoothFollowAllows to interpolate smoothly to another object's transform
DeleteBoxWill destroy objects with the Deletable component when entering the box
DeletableThe GameObject this component is attached to will be deleted when it enters or intersects with a DeleteBox
DropListenerAdd to receive file drop events for uploading
SpatialTriggerUse to raise event if an object enters a specific space or area. You can also use Physics events
SpatialTriggerReceiverUse to receive events from SpatialTrigger

Physics

Physics is implemented using Rapier.

NameDescription
RigidbodyAdd to make an object react to gravity (or be kinematic and static)
BoxColliderA Box collider shape that objects can collide with or raise trigger events when set to trigger
SphereColliderSee BoxCollider
CapsuleColliderSee BoxCollider
MeshColliderSee BoxCollider
Physics MaterialsPhysics materials can be used to define e.g. the bouncyness of a collider

XR / WebXR

',18)),t("p",null,[r(d,{to:"/xr.html"},{default:n(()=>e[3]||(e[3]=[o("Read the XR docs")])),_:1})]),t("table",null,[e[15]||(e[15]=t("thead",null,[t("tr",null,[t("th",null,"Name"),t("th",null,"Description")])],-1)),t("tbody",null,[e[6]||(e[6]=t("tr",null,[t("td",null,[t("code",null,"WebXR")]),t("td",null,"Add to scene for VR, AR and Passthrough support as well as rendering Avatar models")],-1)),t("tr",null,[t("td",null,[r(d,{to:"/everywhere-actions.html"},{default:n(()=>e[4]||(e[4]=[t("code",null,"USDZExporter",-1)])),_:1})]),e[5]||(e[5]=t("td",null,"Add to enable USD and Quicklook support",-1))]),e[7]||(e[7]=t("tr",null,[t("td",null,[t("code",null,"XRFlag")]),t("td",null,"Control when objects are visible, e.g. only in VR or AR or only in ThirdPerson")],-1)),e[8]||(e[8]=t("tr",null,[t("td",null,[t("code",null,"WebARSessionRoot")]),t("td",null,"Handles placement and scale of your scene in AR mode")],-1)),e[9]||(e[9]=t("tr",null,[t("td",null,[t("code",null,"WebARCameraBackground")]),t("td",null,"Add to access the AR camera image and apply effects or use it for rendering")],-1)),e[10]||(e[10]=t("tr",null,[t("td",null,[t("code",null,"WebXRImageTracking")]),t("td",null,"Assign images to be tracked and optionally instantiate an object at the image position")],-1)),e[11]||(e[11]=t("tr",null,[t("td",null,[t("code",null,"WebXRPlaneTracking")]),t("td",null,"Create plane meshes or colliders for tracked planes")],-1)),e[12]||(e[12]=t("tr",null,[t("td",null,[t("code",null,"XRControllerModel")]),t("td",null,"Can be added to render device controllers or hand models (will be created by default when enabled in the WebXR component)")],-1)),e[13]||(e[13]=t("tr",null,[t("td",null,[t("code",null,"XRControllerMovement")]),t("td",null,"Can be added to provide default movement and teleport controls")],-1)),e[14]||(e[14]=t("tr",null,[t("td",null,[t("code",null,"XRControllerFollow")]),t("td",null,"Can be added to any object in the scene and configured to follow either left or right hands or controllers")],-1))])]),e[21]||(e[21]=a('

Debugging

NameDescription
GridHelperDraws a grid
BoxGizmoDraws a box
AxesHelperDraws XYZ axes
Note: When you're writing custom code you can use the static Gizmos methods for drawing debugging lines and shapes

Runtime File Input/Output

NameDescription
GltfExportExperimental! Use to export gltf from web runtime.
DropListenerReceive file drop events for uploading and networking

UI

Spatial UI components are mapped from Unity UI (Canvas, not UI Toolkit) to three-mesh-ui. UI can be animated.

NameDescription
CanvasUnity's UI system. Needs to be in World Space mode right now.
Text (Legacy)Render Text using Unity's UI Text component. Custom fonts are supported, a font atlas will be automatically generated on export. Use the font settings to control which characters are included in the atlas.
Note: In Unity make sure to use the Legacy/Text component (TextMeshPro is not supported at the moment)
ButtonReceives click events - use the onClick event to react to it. It can be added too 3D scene objects as well.
Note: Make sure to use the Legacy/Text component in the Button (or create the Button via the UI/Legacy/Button Unity context menu since TextMeshPro is not supported at the moment)
ImageRenders a sprite image
RawImageRenders a texture
InputFieldAllows text input

Note: Depending on your project, often a mix of spatial and 2D UI makes sense for cross-platform projects where VR, AR, and screens are supported. Typically, you'd build the 2D parts with HTML for best accessibility, and the 3D parts with geometric UIs that also support depth offsets (e.g. button hover states and the like).

Other

NameDescription
SceneSwitcherHandles loading and unloading of other scenes or prefabs / glTF files. Has features to preload, change scenes via swiping, keyboard events or URL navigation

Editor Only

NameDescription
ExportInfoMain component for managing the web project(s) to e.g. install or start the web app
EditorSyncAdd to enable networking material or component value changes to the running three.js app directly from the Unity Editor without having to reload
',12))])}const g=i(h,[["render",p],["__file","component-reference.html.vue"]]),b=JSON.parse(`{"path":"/component-reference.html","title":"Needle Core Components","lang":"en-US","frontmatter":{"title":"Needle Core Components","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/needle core components.png"}],["meta",{"name":"og:description","content":"---\\nHere is a overview of some of the components that we provide. Many of them map to components and functionality in Unity, Blender or other integrations.\\nFor a complete list please have a look at our API docs.\\nYou can always add your own components or add wrappers for Unity components we haven't provided yet.\\nLearn more in the Scripting section of our docs."}]],"description":"---\\nHere is a overview of some of the components that we provide. Many of them map to components and functionality in Unity, Blender or other integrations.\\nFor a complete list please have a look at our API docs.\\nYou can always add your own components or add wrappers for Unity components we haven't provided yet.\\nLearn more in the Scripting section of our docs."},"headers":[{"level":2,"title":"Audio","slug":"audio","link":"#audio","children":[]},{"level":2,"title":"Animation","slug":"animation","link":"#animation","children":[]},{"level":2,"title":"Rendering","slug":"rendering","link":"#rendering","children":[{"level":3,"title":"Postprocessing","slug":"postprocessing","link":"#postprocessing","children":[]}]},{"level":2,"title":"Networking","slug":"networking","link":"#networking","children":[]},{"level":2,"title":"Interaction","slug":"interaction","link":"#interaction","children":[]},{"level":2,"title":"Physics","slug":"physics","link":"#physics","children":[]},{"level":2,"title":"XR / WebXR","slug":"xr-webxr","link":"#xr-webxr","children":[]},{"level":2,"title":"Debugging","slug":"debugging","link":"#debugging","children":[]},{"level":2,"title":"Runtime File Input/Output","slug":"runtime-file-input-output","link":"#runtime-file-input-output","children":[]},{"level":2,"title":"UI","slug":"ui","link":"#ui","children":[]},{"level":2,"title":"Other","slug":"other","link":"#other","children":[]},{"level":2,"title":"Editor Only","slug":"editor-only","link":"#editor-only","children":[]}],"git":{"updatedTime":1727182460000},"filePathRelative":"component-reference.md"}`);export{g as comp,b as data}; diff --git a/assets/contribution-header-B7v_pWCC.js b/assets/contribution-header-B7v_pWCC.js new file mode 100644 index 000000000..61683eed1 --- /dev/null +++ b/assets/contribution-header-B7v_pWCC.js @@ -0,0 +1 @@ +import{_ as l,o as r,c as n,a as t,t as o,g as s,n as c,f as _}from"./app-CRZRGfEE.js";const d={__name:"contribution-header",props:{title:String,url:String,page:String,author:String,profileImage:String,githubUrl:String,gradient:Boolean},setup(a,{expose:i}){i();const e={};return Object.defineProperty(e,"__isScriptSetup",{enumerable:!1,value:!0}),e}},u={class:"contribution"},h={class:"profile"},f=["src"],g=["href"],m={class:"links"},b=["href"],p={key:0,class:"title"};function S(a,i,e,v,k,y){return r(),n("div",u,[t("div",{class:c(["header",e.gradient?"gradient":""])},[t("div",h,[t("img",{src:e.profileImage,alt:"profile image"},null,8,f),t("a",{class:"authorname",href:e.page},[t("span",null,o(e.author),1)],8,g)]),t("div",m,[e.githubUrl?(r(),n("a",{key:0,href:e.githubUrl,target:"_blank",rel:"noopener noreferrer"},"View on Github",8,b)):s("",!0)])],2),e.title?(r(),n("div",p,[t("h2",null,o(e.title),1)])):s("",!0),_(a.$slots,"default",{},void 0,!0)])}const x=l(d,[["render",S],["__scopeId","data-v-543822ed"],["__file","contribution-header.vue"]]);export{x as default}; diff --git a/assets/contribution-listentry-CYemCd1W.js b/assets/contribution-listentry-CYemCd1W.js new file mode 100644 index 000000000..33680c564 --- /dev/null +++ b/assets/contribution-listentry-CYemCd1W.js @@ -0,0 +1 @@ +import{_ as n,o as s,c as o,a as c,t as i}from"./app-CRZRGfEE.js";const _={__name:"contribution-listentry",props:{title:String,url:String},setup(r,{expose:t}){t();const e={};return Object.defineProperty(e,"__isScriptSetup",{enumerable:!1,value:!0}),e}},a=["href"];function l(r,t,e,u,p,d){return s(),o("a",{class:"entry",href:e.url},[c("div",null,i(e.title),1)],8,a)}const b=n(_,[["render",l],["__scopeId","data-v-bcc3d6f6"],["__file","contribution-listentry.vue"]]);export{b as default}; diff --git a/assets/contribution-preview-BGt1xWap.js b/assets/contribution-preview-BGt1xWap.js new file mode 100644 index 000000000..77a3dc586 --- /dev/null +++ b/assets/contribution-preview-BGt1xWap.js @@ -0,0 +1 @@ +import{_ as s,o as c,c as a,a as i,t as l,f as _}from"./app-CRZRGfEE.js";const p={__name:"contribution-preview",props:{title:String,pageUrl:String},setup(t,{expose:r}){r();const e=t;function o(){window.location.href=e.pageUrl}const n={props:e,onClick:o};return Object.defineProperty(n,"__isScriptSetup",{enumerable:!1,value:!0}),n}},d={class:"title"},u={class:"content"};function f(t,r,e,o,n,v){return c(),a("div",{class:"preview",onClick:o.onClick},[i("div",d,l(e.title),1),i("div",u,[_(t.$slots,"default",{},void 0,!0)])])}const m=s(p,[["render",f],["__scopeId","data-v-f801cb6e"],["__file","contribution-preview.vue"]]);export{m as default}; diff --git a/assets/contributions-author-BSwyEtB9.js b/assets/contributions-author-BSwyEtB9.js new file mode 100644 index 000000000..20e8b645a --- /dev/null +++ b/assets/contributions-author-BSwyEtB9.js @@ -0,0 +1 @@ +import{_ as a,r as u,o as n,c as i,g as l,b as c,a as r,f as _,F as d}from"./app-CRZRGfEE.js";const f={__name:"contributions-author",props:{name:String,url:String,githubUrl:String,profileImage:String,overviewLink:String},setup(o,{expose:t}){t();const e={};return Object.defineProperty(e,"__isScriptSetup",{enumerable:!1,value:!0}),e}},g=["href"],h={class:"previews"};function m(o,t,e,p,v,b){const s=u("contribution-header");return n(),i(d,null,[e.overviewLink?(n(),i("a",{key:0,href:e.overviewLink,class:"overview-link"},"โ—€ Overview",8,g)):l("",!0),c(s,{profileImage:e.profileImage,author:e.name,githubUrl:e.githubUrl},null,8,["profileImage","author","githubUrl"]),r("div",h,[_(o.$slots,"default")]),t[0]||(t[0]=r("div",{class:"footer"},[r("a",{href:"https://github.com/needle-tools/needle-engine-support/discussions/new?category=share"},"Add your contribution")],-1))],64)}const k=a(f,[["render",m],["__file","contributions-author.vue"]]);export{k as default}; diff --git a/assets/contributions-overview-D_rfeOIs.js b/assets/contributions-overview-D_rfeOIs.js new file mode 100644 index 000000000..322f5121b --- /dev/null +++ b/assets/contributions-overview-D_rfeOIs.js @@ -0,0 +1 @@ +import{_ as o,o as t,c as s,f as r}from"./app-CRZRGfEE.js";const c={},n={class:"list"};function i(e,_){return t(),s("div",n,[r(e.$slots,"default")])}const l=o(c,[["render",i],["__file","contributions-overview.vue"]]);export{l as default}; diff --git a/assets/contributions.html-DddtFv1E.js b/assets/contributions.html-DddtFv1E.js new file mode 100644 index 000000000..fd6d36591 --- /dev/null +++ b/assets/contributions.html-DddtFv1E.js @@ -0,0 +1 @@ +import{_ as c,r,o as l,c as u,a,d as m,b as t,w as o}from"./app-CRZRGfEE.js";const d={};function b(p,n){const e=r("contribution-listentry"),i=r("contribution-header"),s=r("contributions-overview");return l(),u("div",null,[n[0]||(n[0]=a("h1",null,"Community Scripts",-1)),n[1]||(n[1]=a("p",null,[m("To contribute a script, please create a new discussion in the "),a("a",{href:"https://github.com/needle-tools/needle-engine-support/discussions/categories/share",target:"_blank",rel:"noopener noreferrer"},"Share category")],-1)),t(s,null,{default:o(()=>[t(i,{url:"https://github.com/llllkatjallll",author:"llllkatjallll",page:"/docs/community/contributions/llllkatjallll",profileImage:"https://avatars.githubusercontent.com/u/38395689?s=100&u=7ce0fef973c4819c4f07823568d6f6061abfe410&v=4"},{default:o(()=>[t(e,{title:"Custom VR Button, that appears only on headsets and not on mobile phones",url:"/docs/community/contributions/llllkatjallll/custom-vr-button-that-appears-only-on-headsets-and-not-on-mobile-phones"}),t(e,{title:"Set fallback material for USDZ exporter",url:"/docs/community/contributions/llllkatjallll/set-fallback-material-for-usdz-exporter"})]),_:1}),t(i,{url:"https://github.com/ROBYER1",author:"ROBYER1",page:"/docs/community/contributions/robyer1",profileImage:"https://avatars.githubusercontent.com/u/10745594?s=100&u=daf2c8b5dad729e556ae2a01c721672b24bc108a&v=4"},{default:o(()=>[t(e,{title:"Microphone access in a browser window (and streamed playback)",url:"/docs/community/contributions/robyer1/microphone-access-in-a-browser-window-and-streamed-playback"}),t(e,{title:"AR Move/Scale/Rotate Controls for Needle on Mobile",url:"/docs/community/contributions/robyer1/ar-move-scale-rotate-controls-for-needle-on-mobile"})]),_:1}),t(i,{url:"https://github.com/ericcraft-mh",author:"ericcraft-mh",page:"/docs/community/contributions/ericcraft-mh",profileImage:"https://avatars.githubusercontent.com/u/99364056?s=100&v=4"},{default:o(()=>[t(e,{title:"QuickLook Vertical Image Tracker",url:"/docs/community/contributions/ericcraft-mh/quicklook-vertical-image-tracker"})]),_:1}),t(i,{url:"https://github.com/krisrok",author:"krisrok",page:"/docs/community/contributions/krisrok",profileImage:"https://avatars.githubusercontent.com/u/3404365?s=100&u=7025bf7e83b4a3cd72dc2cae9cec729080ee8970&v=4"},{default:o(()=>[t(e,{title:"Always open in specific browser",url:"/docs/community/contributions/krisrok/always-open-in-specific-browser"})]),_:1}),t(i,{url:"https://github.com/marwie",author:"marwie",page:"/docs/community/contributions/marwie",profileImage:"https://avatars.githubusercontent.com/u/5083203?s=100&v=4"},{default:o(()=>[t(e,{title:"Camera Video Background",url:"/docs/community/contributions/marwie/camera-video-background"}),t(e,{title:"USDZ: Hide Object on Start",url:"/docs/community/contributions/marwie/usdz-hide-object-on-start"}),t(e,{title:"Everywhere Action: Emphasize on Click",url:"/docs/community/contributions/marwie/everywhere-action-emphasize-on-click"}),t(e,{title:"Control a Timeline by scroll",url:"/docs/community/contributions/marwie/control-a-timeline-by-scroll"}),t(e,{title:"Code Contribution Example",url:"/docs/community/contributions/marwie/code-contribution-example"})]),_:1}),t(i,{url:"https://github.com/kipash",author:"kipash",page:"/docs/community/contributions/kipash",profileImage:"https://avatars.githubusercontent.com/u/30328735?s=100&u=f28398f4575da1835d1c710d14763c69418cd0fa&v=4"},{default:o(()=>[t(e,{title:"Calculate pointer world position",url:"/docs/community/contributions/kipash/calculate-pointer-world-position"})]),_:1}),t(i,{url:"https://github.com/Web3Kev",author:"Web3Kev",page:"/docs/community/contributions/web3kev",profileImage:"https://avatars.githubusercontent.com/u/106066970?s=100&v=4"},{default:o(()=>[t(e,{title:"Vertical Move in VR using the right joystick (Quest)",url:"/docs/community/contributions/web3kev/vertical-move-in-vr-using-the-right-joystick-quest"}),t(e,{title:"Squeeze to Scale (Object or World) in VR",url:"/docs/community/contributions/web3kev/squeeze-to-scale-object-or-world-in-vr"}),t(e,{title:"Network instantiation of multiple objects",url:"/docs/community/contributions/web3kev/network-instantiation-of-multiple-objects"})]),_:1})]),_:1})])}const f=c(d,[["render",b],["__file","contributions.html.vue"]]),y=JSON.parse('{"path":"/community/contributions","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/community: contributions.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{f as comp,y as data}; diff --git a/assets/control-a-timeline-by-scroll.html-GAfS3g38.js b/assets/control-a-timeline-by-scroll.html-GAfS3g38.js new file mode 100644 index 000000000..3ff733dbe --- /dev/null +++ b/assets/control-a-timeline-by-scroll.html-GAfS3g38.js @@ -0,0 +1,54 @@ +import{_ as t,r as n,o as h,c as l,a as s,b as k,e}from"./app-CRZRGfEE.js";const p={};function r(d,i){const a=n("contribution-header");return h(),l("div",null,[i[0]||(i[0]=s("p",null,[s("a",{href:"/docs/community/contributions"},"Overview")],-1)),k(a,{url:"https://github.com/marwie",author:"marwie",page:"/docs/community/contributions/marwie",profileImage:"https://avatars.githubusercontent.com/u/5083203?s=100&v=4",githubUrl:"https://github.com/needle-tools/needle-engine-support/discussions/155",title:"Control a Timeline by scroll",gradient:"True"}),i[1]||(i[1]=e(`

Use the mouse wheel or touch delta to update a timeline's time.

import { Behaviour, PlayableDirector, serializeable } from "@needle-tools/engine";
+import { Mathf } from "@needle-tools/engine";
+
+// Example of setting a timeline's time 
+// without relying on any HTML elements.
+// Here we directly use the mousewheel scroll and the touch delta
+
+export class ScrollTimeline_2 extends Behaviour {
+
+    @serializeable(PlayableDirector)
+    timeline?: PlayableDirector;
+
+    @serializeable()
+    scrollSpeed: number = 0.5;
+
+    @serializeable()
+    lerpSpeed: number = 2.5;
+
+    private targetTime: number = 0;
+
+    start() {
+
+        this.timeline?.pause();
+
+        // Grab the mousewheel event
+        window.addEventListener("wheel", (evt: WheelEvent) => this.updateTime(evt.deltaY));
+
+        // Touch events are a bit more complicated
+        // We need to keep track of the last touch position
+        // and calculate the delta between the current and the last position
+        let lastTouchPosition = -1;
+        window.addEventListener("touchmove", (evt: TouchEvent) => {
+            const delta = evt.touches[0].clientY - lastTouchPosition;
+            // We only want to apply the delta if it's not TOO big
+            // e.g. when the user is scrolling the page
+            if (delta < 10) this.updateTime(-delta);
+            // Update the last touch position
+            lastTouchPosition = evt.touches[0].clientY;
+        });
+    }
+
+    private updateTime(delta) {
+        if (!this.timeline) return;
+        this.targetTime += delta * 0.01 * this.scrollSpeed;
+        this.targetTime = Mathf.clamp(this.targetTime, 0, this.timeline.duration);
+    }
+
+    onBeforeRender(): void {
+        if (!this.timeline) return;
+        this.timeline.pause();
+        this.timeline.time = Mathf.lerp(this.timeline.time, this.targetTime, this.lerpSpeed * this.context.time.deltaTime);
+        this.timeline.evaluate();
+    }
+}
`,2))])}const C=t(p,[["render",r],["__file","control-a-timeline-by-scroll.html.vue"]]),g=JSON.parse('{"path":"/community/contributions/marwie/control-a-timeline-by-scroll","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/marwie: control a timeline by scroll.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{C as comp,g as data}; diff --git a/assets/copyright-ClhS8G3R.js b/assets/copyright-ClhS8G3R.js new file mode 100644 index 000000000..da7abbb8b --- /dev/null +++ b/assets/copyright-ClhS8G3R.js @@ -0,0 +1 @@ +import{_ as o,o as a,c as s,d as c,a as t}from"./app-CRZRGfEE.js";const n={},r={class:"footer"};function l(i,e,d,p,_,f){return a(),s("div",r,e[0]||(e[0]=[c(" ยฉ2024 Needle Tools GmbH ยท "),t("a",{class:"no-external-link-icon",target:"_blank",href:"https://needle.tools/contact"},"About ยท ",-1),t("a",{class:"no-external-link-icon",target:"_blank",href:"https://needle.tools/contact#privacy-policy"},"Privacy Policy",-1)]))}const h=o(n,[["render",l],["__scopeId","data-v-66df4b0b"],["__file","copyright.vue"]]);export{h as default}; diff --git a/assets/custom-loading-style-s1K1my2z.js b/assets/custom-loading-style-s1K1my2z.js new file mode 100644 index 000000000..7aab91972 --- /dev/null +++ b/assets/custom-loading-style-s1K1my2z.js @@ -0,0 +1 @@ +const s="/docs/imgs/custom-loading-style.webp";export{s as _}; diff --git a/assets/custom-vr-button-that-appears-only-on-headsets-and-not-on-mobile-phones.html-Cyk2JJNy.js b/assets/custom-vr-button-that-appears-only-on-headsets-and-not-on-mobile-phones.html-Cyk2JJNy.js new file mode 100644 index 000000000..017cfc892 --- /dev/null +++ b/assets/custom-vr-button-that-appears-only-on-headsets-and-not-on-mobile-phones.html-Cyk2JJNy.js @@ -0,0 +1,15 @@ +import{_ as t,r as n,o as e,c as l,a as i,b as h,e as k}from"./app-CRZRGfEE.js";const p={};function o(r,s){const a=n("contribution-header");return e(),l("div",null,[s[0]||(s[0]=i("p",null,[i("a",{href:"/docs/community/contributions"},"Overview")],-1)),h(a,{url:"https://github.com/llllkatjallll",author:"llllkatjallll",page:"/docs/community/contributions/llllkatjallll",profileImage:"https://avatars.githubusercontent.com/u/38395689?s=100&u=7ce0fef973c4819c4f07823568d6f6061abfe410&v=4",githubUrl:"https://github.com/needle-tools/needle-engine-support/discussions/198",title:"Custom VR Button, that appears only on headsets and not on mobile phones",gradient:"True"}),s[1]||(s[1]=k(`

I combined two checks - Needle's check to see if it's a mobile device (this way, you can exclude desktops), and then a second check that uses user agent info to see if it's one of the most common mobile systems. Result: the button does not appear on mobile phones, but it is visible on Quest and Pico ๐Ÿ™‚

P.S: I am using Svelte for 2D UI handling.

import { isMobileDevice, NeedleXRSession } from "@needle-tools/engine";
+
+...
+
+// check if this is a mobile phone
+function isMobilePhone() {
+    return /Mobi|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
+}
+
+...
+
+// show the button, if the device is not a mobile phone and VR is supported
+{#if  isMobileDevice() && !isMobilePhone() && $haveVR }
+    <VrButton buttonFunction={() => StartVR()} />
+{/if}
`,3))])}const g=t(p,[["render",o],["__file","custom-vr-button-that-appears-only-on-headsets-and-not-on-mobile-phones.html.vue"]]),c=JSON.parse('{"path":"/community/contributions/llllkatjallll/custom-vr-button-that-appears-only-on-headsets-and-not-on-mobile-phones","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/llllkatjallll: custom vr button that appears only on headsets and not on mobile phones.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{g as comp,c as data}; diff --git a/assets/debugging.html-x99TIVp3.js b/assets/debugging.html-x99TIVp3.js new file mode 100644 index 000000000..ec54d6a96 --- /dev/null +++ b/assets/debugging.html-x99TIVp3.js @@ -0,0 +1,12 @@ +import{_ as n,r as l,o,c as r,e as s,a,d as i,b as h,w as d}from"./app-CRZRGfEE.js";const p="/docs/debugging/vscode-start-debugging.webp",g={};function u(c,e){const t=l("RouteLink");return o(),r("div",null,[e[5]||(e[5]=s('

Useful resources for working with glTF

To inspect glTF or glb files online:

To inspect them locally:

Built-in URL parameters

Debug Flags can be appended as URL query parameters.
Use ?help to get a list of ALL parameters available.

Here are some of the most commonly used:

  • help print all available url parameter in the console
  • console opens an on-screen dev console, useful for mobile debugging
  • printGltf logs loaded gltf files to the console
  • stats shows FPS module and logs threejs renderer stats every few seconds
  • showcolliders visualizes physics colliders
  • gizmos enables gizmo rendering (e.g. when using BoxCollider or AxesHelper components)
  • and a lot more: please use help to see them all

Debug Methods

',10)),a("p",null,[e[1]||(e[1]=i("Needle Engine also has some very powerful and useful debugging methods that are part of the static ")),e[2]||(e[2]=a("code",null,"Gizmos",-1)),e[3]||(e[3]=i(" class. See the ")),h(t,{to:"/scripting.html#gizmos"},{default:d(()=>e[0]||(e[0]=[i("scripting documentation")])),_:1}),e[4]||(e[4]=i(" for more information."))]),e[6]||(e[6]=s(`

Local Testing of release builds

  • First, install http-server: npm install -g http-server
  • make a build (development or production)
  • open the dist directory with a commandline tool
  • run http-server -g | -g enables gzip support
  • optional: if you want to test WebXR, generate a self-signed SSL certificate, then run http-server -g -S to enable https (required for WebXR).

VSCode

You can attach VSCode to the running local server to set breakpoints and debug your code. You can read more about debugging with VSCode here.

Create a launch.json file at .vscode/launch.json in your web project with the following content:

{
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "type": "chrome",
+            "request": "launch",
+            "name": "Attach Chrome",
+            "url": "https://localhost:3000",
+            "webRoot": "\${workspaceFolder}"
+        }
+    ]
+}

If you have changed the port on which your server starts make sure to update the url field accordingly.
You can then start your local server from within VSCode:

Mobile

Android Debugging

For Android debugging, you can attach Chrome Dev Tools to your device and see logs right from your PC. You have to switch your device into development mode and connect it via USB.

See the official chrome documentation here

  • Make sure Developer Mode is enabled on your phone
  • Connect your phone to your computer via USB
  • Open this url in your browser chrome://inspect/#devices
  • On your mobile device allow the USB connection to your computer
  • On your computer in chrome you should see a list of open tabs after a while (on chrome://inspect/#devices)
  • Click Inspect on the tab you want to debug

iOS Debugging

For easy iOS debugging add the ?console URL parameter to get a useful on-screen JavaScript console.

If you have a Mac, you can also attach to Safari (similar to the Android workflow above).

WebXR usage and debugging on iOS requires using a third-party browser: Mozilla WebXR Viewer.

Quest Debugging

Quest is just an Android device - see the Android Debugging section for steps.

',19))])}const b=n(g,[["render",u],["__file","debugging.html.vue"]]),f=JSON.parse('{"path":"/debugging.html","title":"How To Debug","lang":"en-US","frontmatter":{"title":"How To Debug","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/how to debug.png"}],["meta",{"name":"og:description","content":"---\\nTo inspect glTF or glb files online:"}]],"description":"---\\nTo inspect glTF or glb files online:"},"headers":[{"level":2,"title":"Useful resources for working with glTF","slug":"useful-resources-for-working-with-gltf","link":"#useful-resources-for-working-with-gltf","children":[]},{"level":2,"title":"Built-in URL parameters","slug":"built-in-url-parameters","link":"#built-in-url-parameters","children":[]},{"level":2,"title":"Debug Methods","slug":"debug-methods","link":"#debug-methods","children":[]},{"level":2,"title":"Local Testing of release builds","slug":"local-testing-of-release-builds","link":"#local-testing-of-release-builds","children":[]},{"level":2,"title":"VSCode","slug":"vscode","link":"#vscode","children":[]},{"level":2,"title":"Mobile","slug":"mobile","link":"#mobile","children":[{"level":3,"title":"Android Debugging","slug":"android-debugging","link":"#android-debugging","children":[]},{"level":3,"title":"iOS Debugging","slug":"ios-debugging","link":"#ios-debugging","children":[]},{"level":3,"title":"Quest Debugging","slug":"quest-debugging","link":"#quest-debugging","children":[]}]}],"git":{"updatedTime":1700724672000},"filePathRelative":"debugging.md"}');export{b as comp,f as data}; diff --git a/assets/deployment.html-C3wlSpNe.js b/assets/deployment.html-C3wlSpNe.js new file mode 100644 index 000000000..d4e8d7ada --- /dev/null +++ b/assets/deployment.html-C3wlSpNe.js @@ -0,0 +1,4 @@ +import{_ as a}from"./texture-compression-BuEaeBZn.js";import{_ as s}from"./ktx-env-variable-DxwKzzNo.js";import{_ as r,r as l,o as d,c as p,e as o,a as t,d as c,b as h}from"./app-CRZRGfEE.js";const i="/docs/imgs/unity-texture-compression.jpg",m="/docs/imgs/unity-texture-compression-options.jpg",u="/docs/imgs/unity-mesh-compression-component.jpg",g="/docs/imgs/unity-mesh-simplification.jpg",y="/docs/imgs/unity-progressive-textures.jpg",b="/docs/imgs/unity-lods-settings-1.jpg",f="/docs/imgs/unity-lods-settings-2.jpg",w="/docs/deployment/deploytoglitch-1.jpg",v="/docs/deployment/deploytoglitch-2.jpg",k="/docs/blender/deploy_to_glitch.webp",x="/docs/deployment/deploytonetlify-2.jpg",T="/docs/deployment/deploytonetlify.jpg",_="/docs/deployment/deploytoftp.jpg",j="/docs/deployment/deploytoftp2.jpg",D="/docs/deployment/deploytoftp3.jpg",P="/docs/deployment/buildoptions_gzip.jpg",F="/docs/deployment/deploytogithubpages.jpg",G="/docs/deployment/deploytofacebookinstantgames.jpg",I="/docs/deployment/deploytofacebookinstantgames-hosting.jpg",U="/docs/deployment/deploytofacebookinstantgames-upload.jpg",N="/docs/deployment/facebookinstantgames-1.jpg",B="/docs/deployment/facebookinstantgames-2.jpg",C="/docs/deployment/facebookinstantgames-3.jpg",S="/docs/imgs/unity-build-window-menu.jpg",O="/docs/imgs/unity-build-window.jpg",A={},z={class:"hint-container details"};function E(M,e){const n=l("video-embed");return d(),p("div",null,[e[2]||(e[2]=o('

What does deployment mean?

Deployment is the process of making your application available to the public on a website. Needle Engine ensures that your project is as small and fast as possible by using the latest compression techniques such as KTX2, Draco, and Meshopt.

Available Deployment Targets

Feel something is missing?

Please let us know in our discord!

Development Builds

See guides above on how to access the options from within your Editor (e.g. Unity or Blender).

The main difference to a production build is that it does not perform ktx2 and draco compression (for reduction of file size and loading speed) as well as the option to progressively load high-quality textures.

We generally recommend making production builds for optimized file size and loading speed (see more information below).

Production Builds

To make a production build, you need to have toktx installed, which provides texture compression using the KTX2 supercompression format. Please go to the toktx Releases Page and download and install the latest version (v4.1.0 at the time of writing). You may need to restart Unity after installing it.
If you're sure that you have installed toktx and it's part of your PATH but still can't be found, please restart your machine and try build again.

Advanced: Custom glTF extensions

If you plan on adding your own custom glTF extensions, building for production requires handling those in gltf-transform. See @needle-tools/gltf-build-pipeline for reference.

Optimization and Compression Options

Texture compression

Production builds will by default compress textures using KTX2 (either ETC1S or UASTC depending on their usage in the project)
but you can also select WebP compression and select a quality level.

How do I choose between ETC1S, UASTC and WebP compression?

FormatETC1SUASTCWebP
GPU Memory UsageLowLowHigh (uncompressed)
File SizeLowHighVery low
QualityMediumVery highDepends on quality setting
Typical usageWorks for everything, but best for color texturesHigh-detail data textures: normal maps, roughness, metallic, etc.Files where ETC1S quality is not sufficient but UASTC is too large

You have the option to select texture compression and progressive loading options per Texture by using the Needle Texture Importer in Unity or in the Material tab in Blender.

Unity: How can I set per-texture compression settings?

image
image

Blender: How can I set per-texture compression settings?

Select the material tab. You will see compression options for all textures that are being used by that material.
Texture Compression options in Blender

Toktx can not be found

Windows: Make sure you have added toktx to your system environment variables. You may need to restart your computer after adding it to refresh the environment variables. The default install location is C:\\Program Files\\KTX-Software\\bin
image

Mesh compression

By default, a production build will compress meshes using Draco compression. Use the MeshCompression component to select between draco and mesh-opt per exported glTF.
Additionally you can setup mesh simplification to reduce the polycount for production builds in the mesh import settings (Unity). When viewing your application in the browser, you can append ?wireframe to your URL to preview the meshes.

How do I choose between Draco and Meshopt?

FormatDracoMeshopt
GPU Memory UsageMediumLow
File SizeLowestLow
Animation compressionNoYes
How can I set draco and meshopt compression settings?

Add the MeshCompression component to select which compression should be applied per exported glTF.

image

  • To change compression for the current scene just add it anywhere in your root scene.
  • To change compression for a prefab or NestedGltf add it to a GltfObject or the prefab that is referenced / exported by any of your components.
  • To change compression for a referenced scene just add it to the referenced scene that is exported
Where to find mesh simplification options to reduce the vertex count when building for production?

Select a Mesh and open the Needle importer options to see available options for the selected mesh:
image

Progressive Textures

You can also add the Progressive Texture Settings component anywhere in your scene, to make all textures in your project be progressively loaded. Progressive loading is not applied to lightmaps or skybox textures at this point.

With progressive loading textures will first be loaded using a lower resolution version. A full quality version will be loaded dynamically when the texture becomes visible. This usually reduces initial loading of your scene significantly.

How can I enable progressive texture loading?

Progressive textures can be enabled per texture
or for all textures in your project:

image

Enable for all textures in the project that don't have any other specific setting:

image

Automatic Mesh LODs (Level of Detail)

Since Needle Engine 3.36 we automatically generate LOD meshes and switch between them at runtime. LODs are loaded on demand and only when needed so so this feature both reduces your loading time as well as performance.

Key Beneftis

  • Faster initial loading time
  • Faster rendering time due to less vertices on screen on average
  • Faster raycasting due to the use of LOD meshes

You can either disable LOD generation for your whole project in the Progressive Loading Settings component or in the Mesh Importer settings.

image

image

Deployment Options

Deploy to Glitch ๐ŸŽ

Glitch provides a fast and free way for everyone to host small and large websites. We're providing an easy way to remix and deploy to a new Glitch page (based on our starter), and also to run a minimalistic networking server on the same Glitch page if needed.

You can deploy to glitch by adding the DeployToGlitch component to your scene and following the instructions.

Note that free projects hosted on glitch may not exceed ~100 MB. If you need to upload a larger project consider using a different deployment target.

How do I deploy to Glitch from Unity?
  1. Add the DeployToGlitch component to the GameObject that also has the ExportInfo component.

  2. Click the Create new Glitch Remix button on the component image

  3. Glitch will now create a remix of the template. Copy the URL from your browser
    image

  4. Open Unity again and paste the URL in the Project Name field of your Deploy To Glitch component
    image

  5. Wait a few seconds until Unity has received your deployment key from glitch (this key is safely stored in the .env file on glitch. Do not share it with others, everyone with this key will be able to upload to your glitch website)
    waiting for the key

  6. Once the Deploy Key has been received you can click the Build & Deploy button to upload to glitch.

How do I deploy to Glitch from Blender?

Deploy To Glitch from Blender component

  1. Find the Deploy To Glitch panel in the Scene tab
  2. Click the Remix on glitch button on the component
  3. Your browser will open the glitch project template
  4. Wait for Glitch to generate a new project
  5. Copy paste the project URL in the Blender DeployToGlitch panel as the project name (you can paste the full URL, the panel will extract the necessary information)
  6. On Glitch open the .env file and enter a password in the field Variable Value next to the DEPLOY_KEY
  7. Enter the same password in Blender in the Key field
  8. Click the DeployToGlitch button to build and upload your project to glitch. A browser will open when the upload has finished. Try to refresh the page if it shows black after having opened it.

Troubleshooting Glitch

If you click Create new Glitch Remix and the browser shows an error like there was an error starting the editor you can click OK. Then go to glitch.com and make sure you are signed in. After that you then try clicking the button again in Unity or Blender.

Deploy to Netlify

How do I deploy to Netlify from Unity?

Just add the DeployToNetlify component to your scene and follow the instructions. You can create new projects with the click of a button or by deploying to existing projects.

Deploy to netlify component

Deploy to netlify component

Deploy to Vercel

  1. Create a new project on vercel
  2. Add your web project to a github repository
  3. Add the repository to your project on vercel

See our sample project for the project configuration

Deploy to itch.io

How do I deploy to itch.io from Unity?
  1. Create a new project on itch.io

  2. Set Kind of project to HTML
    image

  3. Add the DeployToItch component to your scene and click the Build button
    image

  4. Wait for the build to finish, it will open a folder with the final zip when it has finished

  5. Upload to final zip to itch.io
    20220920-104629_Create_a_new_project_-itch io-_Google_Chrome-needle

  6. Select This file will be played in the browser
    image

  7. Save your itch page and view the itch project page.
    It should now load your Needle Engine project ๐Ÿ˜Š

Optional settings

image

Itch.io: failed to find index.html

Failed to find index.html

image
If you see this error after uploading your project make sure you do not upload a gzipped index.html. You can disable gzip compression in vite.config.js in your Needle web project folder. Just remove the line with viteCompression({ deleteOriginFile: true }). The build your project again and upload to itch.

Deploy to FTP

How do I deploy to my FTP server from Unity?
  1. Add the DeployToFTP componentยน on a GameObject in your scene (it is good practice to add it to the same GameObject as ExportInfo - but it is not mandatory)
  2. Assign an FTP server asset and fill out server, username, and password if you have not already ยฒ
    This asset contains the access information to your FTP server - you get them when you create a new FTP account at your hosting provider
  3. Click the Build & Deploy button on the DeployToFTP component to build your project and uploading it to your FTP account

Deploy to FTP component in Unity
ยน Deploy to FTP component

Deploy to FTP server asset
ยฒ FTP Server asset containing the access information of your FTP user account

Deploy to FTP component in Unity with server asset assigned
Deploy To FTP component after server asset is assigned. You can directly deploy to a subfolder on your server using the path field

How do I deploy to my FTP server manually?
  1. Open File > Build Settings, select Needle Engine, and click on Build
  2. Wait for the build to complete - the resulting dist folder will open automatically after all build and compression steps have run.
  3. Copy the files from the dist folder to your FTP storage.

That's it! ๐Ÿ˜‰

20220830-003602_explorer-needle

Note: If the result doesn't work when uploaded it might be that your web server does not support serving gzipped files. You have two options to fix the problem:
Option 1: You can try enabling gzip compression on your server using a htaccess file!
Option 2: You can turn gzip compression off in the build settings at File/Build Window and selecting the Needle Engine platform.

Note: If you're getting errors during compression, please let us know and report a bug! If your project works locally and only fails when doing production builds, you can get unstuck right away by doing a Development Build. For that, simply toggle Development Build on in the Build Settings.

Unity build window showing Needle Engine platform

Enabling gzip using a .htaccess file

To enable gzip compression on your FTP server you can create a file named .htaccess in the directory you want to upload to (or a parent directory).
Insert the following code into your .htaccess file and save/upload it to your server:

<IfModule mod_mime.c>
+RemoveType .gz
+AddEncoding gzip .gz
+AddType application/javascript .js.gz

Deploy to Github Pages

`,62)),t("details",z,[e[0]||(e[0]=t("summary",null,"How do I deploy to Github Pages from Unity?",-1)),e[1]||(e[1]=t("p",null,[c("Add the DeployToGithubPages component to your scene and copy-paste the github repository (or github pages url) that you want to deploy to."),t("br"),t("img",{src:F,alt:"Deploy To github pages component"})],-1)),h(n,{src:"https://www.youtube.com/watch?v=Vyk3cWB6u-c"})]),e[3]||(e[3]=o('

Deploy to Facebook Instant Games

With Needle Engine you can build to Facebook Instant Games automatically
No manual adjustments to your web app or game are required.

How do I deploy to Facebook Instant Games from Unity?
  • Add the Deploy To Facebook Instant Games component to your scene: Deploy to facebook instant games component
  • Click the Build For Instant Games button
  • After the build has finished you will get a ZIP file that you can upload to your facebook app.
  • On Facebook add the Instant Games module and go to Instant Games/Web hostingHosting a facebook instant games
  • You can upload your zip using the Upload version button (1). After the upload has finished and the zip has been processed click the Stage for testing button to test your app (2, here the blue button) or Push to production (the button with the star icon) Upload the zip to facebook instant games
  • That's it - you can then click the Play button next to each version to test your game on facebook.
How do I create a app on Facebook (with Instant Games capabilities)
  1. Create a new app and select Other. Then click NextCreate facebook instant games app

  2. Select type Instant GamesCreate facebook instant games app

  3. After creating the app add the Instant Games product Add instant games product

Here you can find the official instant games documentation on facebook.
Note that all you have to do is to create an app with instant games capabilities.
We will take care of everything else and no manual adjustments to your Needle Engine website are required.

Build To Folder

In Unity open File/Build Settings and select Needle Engine for options:

image

image

To build your web project for uploading to any web server you can click Build in the Unity Editor Build Settings Window. You can enable the Development Build checkbox to omit compression (see below) which requires toktx to be installed on your machine.

To locally preview your final build you can use the Preview Build button at the bottom of the window. This button will first perform a regular build and then start a local server in the directory with the final files so you can see what you get once you upload these files to your webserver.

Nodejs is only required during development. The distributed website (using our default vite template) is a static page that doesn't rely on Nodejs and can be put on any regular web server. Nodejs is required if you want to run our minimalistic networking server on the same web server (automatically contained in the Glitch deployment process).


Cross-Platform Deployment Workflows

It's possible to create regular Unity projects where you can build both to Needle Engine and to regular Unity platforms such as Desktop or even WebGL. Our "component mapping" approach means that no runtime logic is modified inside Unity - if you want you can regularily use Play Mode and build to other target platforms. In some cases this will mean that you have duplicate code (C# code and matching TypeScript logic). The amount of extra work through this depends on your project.

Enter Play Mode in Unity
In Project Settings > Needle Engine, you can turn off Override Play Mode and Override Build settings to switch between Needle's build process and Unity's build process:
image

Needle Engine Commandline Arguments for Unity

Needle Engine for Unity supports various commandline arguments to export single assets (Prefabs or Scenes) or to build a whole web project in batch mode (windowsless).

The following list gives a table over the available options:

-scenepath to a scene or a asset to be exported e.g. Assets/path/to/myObject.prefab or Assets/path/to/myScene.unity
-outputPath <path/to/output.glb>set the output path for the build (only valid when building a scene)
-buildProductionrun a production build
-buildDevelopmentrun a development build
-debugopen a console window for debugging
',19))])}const q=r(A,[["render",E],["__file","deployment.html.vue"]]),Y=JSON.parse('{"path":"/deployment.html","title":"Deployment and Optimization","lang":"en-US","frontmatter":{"title":"Deployment and Optimization","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/deployment and optimization.png"}],["meta",{"name":"og:description","content":"---\\nDeployment is the process of making your application available to the public on a website. Needle Engine ensures that your project is as small and fast as possible by using the latest compression techniques such as KTX2, Draco, and Meshopt."}]],"description":"---\\nDeployment is the process of making your application available to the public on a website. Needle Engine ensures that your project is as small and fast as possible by using the latest compression techniques such as KTX2, Draco, and Meshopt."},"headers":[{"level":2,"title":"What does deployment mean?","slug":"what-does-deployment-mean","link":"#what-does-deployment-mean","children":[]},{"level":2,"title":"Available Deployment Targets","slug":"available-deployment-targets","link":"#available-deployment-targets","children":[]},{"level":2,"title":"Development Builds","slug":"development-builds","link":"#development-builds","children":[]},{"level":2,"title":"Production Builds","slug":"production-builds","link":"#production-builds","children":[{"level":3,"title":"Optimization and Compression Options","slug":"optimization-and-compression-options","link":"#optimization-and-compression-options","children":[]},{"level":3,"title":"Texture compression","slug":"texture-compression","link":"#texture-compression","children":[]},{"level":3,"title":"Mesh compression","slug":"mesh-compression","link":"#mesh-compression","children":[]},{"level":3,"title":"Progressive Textures","slug":"progressive-textures","link":"#progressive-textures","children":[]},{"level":3,"title":"Automatic Mesh LODs (Level of Detail)","slug":"automatic-mesh-lods-level-of-detail","link":"#automatic-mesh-lods-level-of-detail","children":[]}]},{"level":2,"title":"Deployment Options","slug":"deployment-options","link":"#deployment-options","children":[{"level":3,"title":"Deploy to Glitch ๐ŸŽ","slug":"deploy-to-glitch","link":"#deploy-to-glitch","children":[]},{"level":3,"title":"Deploy to Netlify","slug":"deploy-to-netlify","link":"#deploy-to-netlify","children":[]},{"level":3,"title":"Deploy to Vercel","slug":"deploy-to-vercel","link":"#deploy-to-vercel","children":[]},{"level":3,"title":"Deploy to itch.io","slug":"deploy-to-itch.io","link":"#deploy-to-itch.io","children":[]},{"level":3,"title":"Deploy to FTP","slug":"deploy-to-ftp","link":"#deploy-to-ftp","children":[]},{"level":3,"title":"Deploy to Github Pages","slug":"deploy-to-github-pages","link":"#deploy-to-github-pages","children":[]},{"level":3,"title":"Deploy to Facebook Instant Games","slug":"deploy-to-facebook-instant-games","link":"#deploy-to-facebook-instant-games","children":[]}]},{"level":2,"title":"Build To Folder","slug":"build-to-folder","link":"#build-to-folder","children":[]},{"level":2,"title":"Cross-Platform Deployment Workflows","slug":"cross-platform-deployment-workflows","link":"#cross-platform-deployment-workflows","children":[]},{"level":2,"title":"Needle Engine Commandline Arguments for Unity","slug":"needle-engine-commandline-arguments-for-unity","link":"#needle-engine-commandline-arguments-for-unity","children":[]}],"git":{"updatedTime":1725399379000},"filePathRelative":"deployment.md"}');export{q as comp,Y as data}; diff --git a/assets/editor-sync.html-B1ATYa5k.js b/assets/editor-sync.html-B1ATYa5k.js new file mode 100644 index 000000000..1f6319657 --- /dev/null +++ b/assets/editor-sync.html-B1ATYa5k.js @@ -0,0 +1 @@ +import{_ as o,r as n,o as a,c as r,e as i,b as s}from"./app-CRZRGfEE.js";const d={};function l(c,e){const t=n("video-embed");return a(),r("div",null,[e[0]||(e[0]=i('

Editor Sync

Needle allows for a very fast, iterative workflow between Unity and the browser. Usually, exports take less than a few seconds. However, once scenes become more complex, for some types of changes (adjusting material properties, nudging objects around), we provide an even faster way to see your changes โ€“ Editor Sync.

How to use Editor Sync

You can enable Editor Sync by adding the EditorSync component to your scene. This component will connect your Unity Editor with your browser project and automatically sync applicable changes between the two.

Tips

Editor Sync is currently an experimental feature. Please let us know about your experience with it! We're eager to hear your feedback.

Video Tutorial

This tutorial shows the Editor Sync workflow in action:

',7)),s(t,{src:"https://www.youtube.com/watch?v=gZX_sqrne8U",limit_height:""})])}const p=o(d,[["render",l],["__file","editor-sync.html.vue"]]),u=JSON.parse('{"path":"/unity/editor-sync.html","title":"Editor Sync","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/unity: editor sync.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[{"level":2,"title":"How to use Editor Sync","slug":"how-to-use-editor-sync","link":"#how-to-use-editor-sync","children":[]},{"level":2,"title":"Video Tutorial","slug":"video-tutorial","link":"#video-tutorial","children":[]}],"git":{"updatedTime":1727106484000},"filePathRelative":"unity/editor-sync.md"}');export{p as comp,u as data}; diff --git a/assets/embedding.html-Bwm82YNo.js b/assets/embedding.html-Bwm82YNo.js new file mode 100644 index 000000000..080c44d32 --- /dev/null +++ b/assets/embedding.html-Bwm82YNo.js @@ -0,0 +1,16 @@ +import{_ as p,r as l,o as r,c,e as o,b as t,w as a,a as e,d as s}from"./app-CRZRGfEE.js";const k={};function u(g,i){const n=l("CodeGroupItem"),h=l("CodeGroup"),d=l("RouteLink");return r(),c("div",null,[i[6]||(i[6]=o('

Needle Engine on your Website

Needle Engine can be used to create new web apps, and can also be integrated into existing websites. In both cases, you'll want to upload your project's distribution folder to a web hoster to make them accessible to the world.

There are several ways to integrate Needle Engine with your website. Which one is better depends on a number of factors, like complexity of your project, if you're using custom scripts or only core components, how much control you have over the target website, what the "trust level" is between you and the target website, and so on.

The two most common workflows are:

  1. Using the "Deploy to ..." components
  2. Embedding a Needle project into an existing website

Quickstart

Try it out now!

If you want to quickly try out how projects made with Needle will look on your website, just add these two lines anywhere on your page for testing:

',7)),t(h,null,{default:a(()=>[t(n,{title:"Embedding Needle"},{default:a(()=>i[0]||(i[0]=[e("div",{class:"language-html","data-highlighter":"shiki","data-ext":"html","data-title":"html",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[e("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[e("code",null,[e("span",{class:"line"},[e("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"<"),e("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE"}},"script"),e("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890"}}," type"),e("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),e("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"module"'),e("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890"}}," src"),e("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),e("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"https://unpkg.com/@needle-tools/engine/dist/needle-engine.min.js"'),e("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},">"),e("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"<"),e("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"/"),e("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE"}},"script"),e("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},">")]),s(` +`),e("span",{class:"line"},[e("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"<"),e("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE"}},"needle-engine"),e("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890"}}," src"),e("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),e("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"https://cloud.needle.tools/api/v1/public/873a48a/10801b111/MusicalInstrument.glb"'),e("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},">")])])])],-1)])),_:1}),t(n,{title:"Using an iframe"},{default:a(()=>i[1]||(i[1]=[e("div",{class:"language-html","data-highlighter":"shiki","data-ext":"html","data-title":"html",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[e("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[e("code",null,[e("span",{class:"line"},[e("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"<"),e("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE"}},"iframe"),e("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890"}}," src"),e("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),e("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"https://engine.needle.tools/samples-uploads/musical-instrument/"')]),s(` +`),e("span",{class:"line"},[e("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890"}}," allow"),e("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),e("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"xr; xr-spatial-tracking; fullscreen;"'),e("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890"}}," width"),e("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),e("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"100%"'),e("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890"}}," height"),e("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),e("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"500px"'),e("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},">")]),s(` +`),e("span",{class:"line"},[e("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"")])])])],-1)])),_:1}),t(n,{title:"Result"},{default:a(()=>i[2]||(i[2]=[e("iframe",{src:"https://engine.needle.tools/samples-uploads/musical-instrument/",allow:"xr; xr-spatial-tracking; fullscreen;",width:"100%",height:"500px",style:{border:"0",outline:"0"}},null,-1)])),_:1})]),_:1}),i[7]||(i[7]=e("h2",{id:"using-the-deploy-to-...-components",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#using-the-deploy-to-...-components"},[e("span",null,'Using the "Deploy to ..." components')])],-1)),i[8]||(i[8]=e("p",null,"Our Needle Engine integrations ship with built-in deployment options. You can deploy your project to Needle Cloud, FTP servers, Glitch, Itch.io, GitHub Pages, and more with just a few clicks.",-1)),e("p",null,[i[4]||(i[4]=s("See the ")),t(d,{to:"/deployment.html"},{default:a(()=>i[3]||(i[3]=[s("Deployment")])),_:1}),i[5]||(i[5]=s(" section for more information on each of these options."))]),i[9]||(i[9]=o(`
  1. Add the "Deploy to ..." component you want to use to your scene in Unity or Blender.
  2. Configure the necessary options and click on "Deploy".
  3. That's it! Your project is now live.

Recommended Workflow

This is the easiest option, and recommended for most workflows โ€“ it's very fast! You can iteratively work on your project on your computer, and then upload a new version to the web in seconds.

Uploading a production build as web app

If you don't want to use our "Deploy to..." components, or there's no component for your particlar workflow, you can do the same process manually. The resulting web app will be identical to what you see in your local server while working on the project.

  1. Make a production build of your web project. This will create a dist/ folder with all necessary files, ready for distribution. It contains all necessary files, including the JavaScript bundle, the HTML file, and any other assets like textures, audio, or video files.

  2. Upload the content of the dist/ folder from your Web Project to your web hoster. You can do this via FTP, SFTP, or any other file transfer method your hoster provides. Look at the documentation of your web hoster for details.

  3. That's it! Your web app is now live.

The folder location influences the URL of your web app.

Depending on your hoster's settings, the folder location and name determine what the URL of your web app is. Here's an example:

  • Your domain https://your-website.com/ points at the folder /var/www/html on your webspace.
  • You upload your files to /var/www/html/my-app so that the index.html file is at /var/www/html/my-app/index.html.
  • The URL of your web app is now https://your-website.com/my-app/.

Embedding a Needle project into an existing website

In some cases, you want a Needle Engine project to be part of an existing web site, for example as a part of a blog post, a product page, or a portfolio. The process is very similar, but instead of uploading the files to the root of your web space, you embed the project into an existing website with a few lines of code.

  1. Make a production build of your web project. This will create a dist/ folder with all necessary files, ready for distribution. It contains all necessary files, including the JavaScript bundle, the HTML file, and any other assets like textures, audio, or video files.

  2. Upload the dist/ folder from your Web Project to your web hoster.

    The folder can be hosted anywhere!

    If you don't have access to your web hoster's file system, or no way to upload files there, you can upload the folder to any other webspace and use the public URL of that in the next step.

  3. Inside your dist folder, you'll find an index.html file. We want to copy some lines from this folder, so open the file in a text editor. Typically, it looks like this:

    <head>
    +    ...
    +    <script type="module" crossorigin src="./assets/index-732f0764.js"></script>
    +    ...
    +</head>
    +<body>
    +    <needle-engine src="assets/scene.glb"></needle-engine>
    +</body>

    There are two important lines here:

    • the JavaScript bundle inside <script>,
    • the <needle-engine> HTML tag.
  4. On the target website, add the <script...> and <needle-engine...> tags as well. Make sure that the paths point at the location where you have uploaded the files to.

    <script type="module" src="/your-upload-folder/assets/index-732f0764.js"></script>
    +<needle-engine src="/your-upload-folder/assets/scene.glb"></needle-engine>
  5. That's it! The scene should now be displayed on your website.

Embedding a Needle project as iframe

When you have limited access to a website, for example when you're using a CMS like WordPress, you can use an iframe to embed a Needle Engine scene into your website. You may know this workflow from embedding YouTube videos or Sketchfab models.

  1. Make a production build of your web project. This will create a dist/ folder with all necessary files, ready for distribution.

  2. Upload the dist/ folder from your Web Project to your web hoster.

    The folder can be hosted anywhere!

    If you don't have access to your web hoster's file system, or no way to upload files there, you can upload the folder to any other webspace and use the public URL of that in the next step.

  3. Add an iframe to your website, pointing to the index.html file in the dist/ folder.

    <iframe
    +    src="https://your-website.com/needle-files/dist/index.html" 
    +    allow="xr; xr-spatial-tracking; fullscreen;">
    +</iframe>

    Permissions inside iframes

    The list inside allow= depends on the features your web app uses. For example, XR applications require xr and xr-spatial-tracking to work inside iframes.

    There may be additional features needed, for example camera; microphone; display-capture; geolocation. See the full list of iframe Permissions Policy directives on MDN.

  4. That's it! The scene should now be displayed on your website.

Embedding scenes that use no custom scripts

When your project uses only core components and no custom scripts, you can directly use Needle Engine from a CDN (content-delivery network).

  1. Add the following snippet to your website, for example as "HTML Block" in your CMS:

    <script type="module" src="https://unpkg.com/@needle-tools/engine/dist/needle-engine.min.js"></script>
    +<needle-engine src="https://cloud.needle.tools/api/v1/public/873a48a/10801b111/MusicalInstrument.glb" background-blurriness="0.8"></needle-engine>
  2. Upload the assets/ folder from your Web Project to your web hoster. Depending on your project settings, this folder contains one or more .glb files and any number of other files like audio, video, skybox and more.

  3. Change the src= attribute of the needle-engine tag to the URL of the .glb file you want to display. Typically, this will be some path like https://your-website.com/assets/MyScene.glb.

  4. That's it! The scene should now be displayed on your website.

Embedding a Needle Cloud web app as iframe

If you deployed your project to Needle Cloud, you can easily display it on your own website with an iframe.

Under construction. This section is not yet complete.

Web Hoster Integrations

Wordpress

  1. Decide on the method you want to use to embed your Needle Engine project. You can either use the "Embedding a Needle project into an existing website" method, or the "Embedding a Needle project as iframe" method.

  2. Upload the content of the dist/ folder from your Web Project to your web hoster. Usually, the Wordpress uploads directory is located at wp-content/uploads/.

    Wordpress Backups

    You can decide if your new project should be at wp-content/uploads/my-project/, or at a different location like my-projects/my-project. This affects if and how your project will be contained in Wordpress backups.

  3. In the page you want to add Needle Engine to, add a HTML block and paste the code snippet as outlined above โ€“ either as script embed, or as iframe.

Shopify

Under construction. Needs to be documented.

Wix

Under construction. Needs to be documented.

Webflow

Under construction. Needs to be documented.

`,27))])}const m=p(k,[["render",u],["__file","embedding.html.vue"]]),b=JSON.parse('{"path":"/embedding.html","title":"Needle Engine on your Website","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/embedding.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[{"level":2,"title":"Quickstart","slug":"quickstart","link":"#quickstart","children":[]},{"level":2,"title":"Using the \\"Deploy to ...\\" components","slug":"using-the-deploy-to-...-components","link":"#using-the-deploy-to-...-components","children":[]},{"level":2,"title":"Uploading a production build as web app","slug":"uploading-a-production-build-as-web-app","link":"#uploading-a-production-build-as-web-app","children":[]},{"level":2,"title":"Embedding a Needle project into an existing website","slug":"embedding-a-needle-project-into-an-existing-website","link":"#embedding-a-needle-project-into-an-existing-website","children":[]},{"level":2,"title":"Embedding a Needle project as iframe","slug":"embedding-a-needle-project-as-iframe","link":"#embedding-a-needle-project-as-iframe","children":[]},{"level":2,"title":"Embedding scenes that use no custom scripts","slug":"embedding-scenes-that-use-no-custom-scripts","link":"#embedding-scenes-that-use-no-custom-scripts","children":[]},{"level":2,"title":"Embedding a Needle Cloud web app as iframe","slug":"embedding-a-needle-cloud-web-app-as-iframe","link":"#embedding-a-needle-cloud-web-app-as-iframe","children":[]},{"level":2,"title":"Wordpress","slug":"wordpress","link":"#wordpress","children":[]},{"level":2,"title":"Shopify","slug":"shopify","link":"#shopify","children":[]},{"level":2,"title":"Wix","slug":"wix","link":"#wix","children":[]},{"level":2,"title":"Webflow","slug":"webflow","link":"#webflow","children":[]}],"git":{"updatedTime":1727778176000},"filePathRelative":"embedding.md"}');export{m as comp,b as data}; diff --git a/assets/ericcraft-mh.html-CjAn6AX_.js b/assets/ericcraft-mh.html-CjAn6AX_.js new file mode 100644 index 000000000..eae1c1826 --- /dev/null +++ b/assets/ericcraft-mh.html-CjAn6AX_.js @@ -0,0 +1,43 @@ +import{_ as n,r as h,o as r,c as p,b as a,w as l,a as i,d as s}from"./app-CRZRGfEE.js";const d={};function o(g,t){const k=h("contribution-preview"),e=h("contributions-author");return r(),p("div",null,[a(e,{overviewLink:"/docs/community/contributions",name:"ericcraft-mh",url:"https://github.com/ericcraft-mh",profileImage:"https://avatars.githubusercontent.com/u/99364056?s=100&v=4",githubUrl:"https://github.com/ericcraft-mh"},{default:l(()=>[a(k,{title:"QuickLook Vertical Image Tracker",pageUrl:"/docs/community/contributions/ericcraft-mh/quicklook-vertical-image-tracker"},{default:l(()=>t[0]||(t[0]=[i("p",null,[s("In cases in which you are using QuickLook Image Tracker and Vertical Imagery you will need to correct the orientation of the model. As noted on the "),i("a",{href:"https://developer.apple.com/documentation/arkit/arkit_in_ios/content_anchors/detecting_images_in_an_ar_experience",target:"_blank",rel:"noopener noreferrer"},"Detecting Images in an AR Experience"),s(" page:")],-1),i("blockquote",null,[i("p",null,[i("code",null,"SCNPlane"),s(" is vertically oriented in its local coordinate space, but "),i("code",null,"ARImageAnchor"),s(" assumes the image is horizontal in its local space, so rotate the plane to match.")])],-1),i("div",{class:"language-ts","data-highlighter":"shiki","data-ext":"ts","data-title":"ts",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[i("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[i("code",null,[i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Behaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," GameObject"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," serializable"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," USDZExporter "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "@needle-tools/engine"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Object3D"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Euler "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "three"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"export"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," class"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," QuickLookObjectsToFix"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," extends"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Behaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," @serializable"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"("),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Object3D"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," objectToFix"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"!:"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Object3D"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," usdzExporter"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"!:"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," USDZExporter"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," startRot"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Euler "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6","--shiki-light-font-weight":"bold","--shiki-dark-font-weight":"bold"}}," new"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Euler"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," onEnable"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"usdzExporter "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," GameObject"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"findObjectOfType"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(USDZExporter)"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"!"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"startRot "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"objectToFix"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"rotation"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"subscribeToBeforeExportEvent"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," onDisable"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"unsubscribeFromBeforeExportEvent"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," subscribeToBeforeExportEvent"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"usdzExporter"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"addEventListener"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"before-export"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"onBeforeExport)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"usdzExporter"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"addEventListener"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"after-export"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"onAfterExport)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," unsubscribeFromBeforeExportEvent"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"usdzExporter"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"removeEventListener"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"before-export"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"onBeforeExport)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"usdzExporter"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"removeEventListener"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"after-export"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"onAfterExport)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," onBeforeExport"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," ="),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," ()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," =>"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"objectToFix"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"updateMatrixWorld"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"objectToFix"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"rotation"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"x "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," -"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Math"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"PI"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," /"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 2"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"objectToFix"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"updateMatrixWorld"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," onAfterExport"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," ="),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," ()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," =>"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"objectToFix"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"updateMatrixWorld"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"objectToFix"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"setRotationFromEuler"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"startRot)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"objectToFix"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"updateMatrixWorld"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}")])])])],-1),i("p",null,[s("Thanks to "),i("a",{href:"https://github.com/llllkatjallll",target:"_blank",rel:"noopener noreferrer"},"llllkatjallll"),s(" as their "),i("a",{href:"https://github.com/needle-tools/needle-engine-support/discussions/184",target:"_blank",rel:"noopener noreferrer"},"Set fallback material for USDZ exporter"),s(" solution helped me come up with a working solution for this.")],-1),i("p",null,"EDIT: Code cleanup and fixes.",-1)])),_:1})]),_:1})])}const C=n(d,[["render",o],["__file","ericcraft-mh.html.vue"]]),E=JSON.parse('{"path":"/community/contributions/ericcraft-mh","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/contributions: ericcraft mh.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{C as comp,E as data}; diff --git a/assets/everywhere-action-emphasize-on-click.html-CVeSGZpb.js b/assets/everywhere-action-emphasize-on-click.html-CVeSGZpb.js new file mode 100644 index 000000000..c65b2224f --- /dev/null +++ b/assets/everywhere-action-emphasize-on-click.html-CVeSGZpb.js @@ -0,0 +1,27 @@ +import{_ as t,r as n,o as h,c as l,a as s,b as e,e as k}from"./app-CRZRGfEE.js";const p={};function r(d,i){const a=n("contribution-header");return h(),l("div",null,[i[0]||(i[0]=s("p",null,[s("a",{href:"/docs/community/contributions"},"Overview")],-1)),e(a,{url:"https://github.com/marwie",author:"marwie",page:"/docs/community/contributions/marwie",profileImage:"https://avatars.githubusercontent.com/u/5083203?s=100&v=4",githubUrl:"https://github.com/needle-tools/needle-engine-support/discussions/157",title:"Everywhere Action: Emphasize on Click",gradient:"True"}),i[1]||(i[1]=k(`

Example for adding custom USDZ behaviours for iOS AR

This is an USDZ / iOS AR only example

export class EmphasizeOnClick extends Behaviour implements UsdzBehaviour {
+
+    @serializable()
+    target?: Object3D;
+
+    @serializable()
+    duration: number = 0.5;
+
+    @serializable()
+    motionType: MotionType = MotionType.bounce;
+
+    beforeCreateDocument() { }
+
+    createBehaviours(ext, model, _context) {
+        if (!this.target) return;
+
+        if (model.uuid === this.gameObject.uuid) {
+            const emphasize = new BehaviorModel("emphasize " + this.name,
+                TriggerBuilder.tapTrigger(this.gameObject),
+                ActionBuilder.emphasize(this.target, this.duration, this.motionType, undefined, "basic"),
+            );
+            ext.addBehavior(emphasize);
+        }
+    }
+
+    afterCreateDocument(_ext, _context) { }
+}
`,3))])}const y=t(p,[["render",r],["__file","everywhere-action-emphasize-on-click.html.vue"]]),g=JSON.parse('{"path":"/community/contributions/marwie/everywhere-action-emphasize-on-click","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/marwie: everywhere action emphasize on click.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{y as comp,g as data}; diff --git a/assets/everywhere-actions.html-ddHbg6za.js b/assets/everywhere-actions.html-ddHbg6za.js new file mode 100644 index 000000000..df0a78d90 --- /dev/null +++ b/assets/everywhere-actions.html-ddHbg6za.js @@ -0,0 +1,24 @@ +import{_ as n,r as l,o as r,c as o,e as a,b as s,a as e}from"./app-CRZRGfEE.js";const h="/docs/imgs/everywhere-actions-component-menu.gif",d={};function p(k,i){const t=l("sample");return r(),o("div",null,[i[0]||(i[0]=a('

What are Everywhere Actions?

Needle's Everywhere Actions are a set of carefully chosen components that allow you to create interactive experiences in Unity without writing a single line of code.
They are designed to serve as building blocks for experiences across the web, mobile and XR, including Augmented Reality on iOS.

From low-level triggers and actions, higher-level complex interactive behaviours can be built.

Supported Platforms

  • Desktop
  • Mobile (Android / iOS)
  • VR Glasses
  • AR Devices
  • iOS AR โ€“ QuickLook (yes, really!)

How do I use Everywhere Actions?

For iOS support add the USDZExporter component to your scene. It is good practice to add it to the same object as the WebXR component (but not mandatory)

To add an action to any object in your scene
select it and then click Add Component > Needle > Everywhere Actions > [Action].

List of Everywhere Actions

ActionDescriptionExample Use Cases
Play Animation on ClickPlays a selected animation state from an Animator. After playing, it can optionally transition to another animation.Product presentations, interactive tutorials, character movement
Change Material on ClickSwitch out one material for others. All objects with that material will be switched together.Product configurators, characters
Look AtMake an object look at the camera.UI elements, sprites, info graphics, billboard effects, clickable hotspots
Play Audio on ClickPlays a selected audio clip.Sound effects, Narration, Museum exhibits
Hide on StartHides an object at scene start for later reveal.
Set Active on ClickShow or hide objects.
Change Transform on ClickMove, rotate or scale an object. Allows for absolute or relative movement.Characters, products, UI animation (use animation for more complex movements)
Audio SourcePlays audio on start and keeps looping. Spatial or non-spatialBackground music, ambient sounds
WebXR Image TrackingTracks an image target and shows or hides objects.AR experiences, product presentations

Samples

Musical Instrument

Demonstrates spatial audio, animation, and interactions.

',14)),s(t,{src:"https://engine.needle.tools/samples-uploads/musical-instrument"}),i[1]||(i[1]=e("h3",{id:"simple-character-controllers",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#simple-character-controllers"},[e("span",null,"Simple Character Controllers")])],-1)),i[2]||(i[2]=e("p",null,"Demonstrates combining animations, look at, and movement.",-1)),s(t,{src:"https://engine.needle.tools/samples-uploads/usdz-characters"}),i[3]||(i[3]=a('

Image Tracking

Demonstrates how to attach 3D content onto a custom image marker. Start the scene below in AR and point your phone's camera at the image marker on a screen, or print it out.

Image Marker

Download Sample Image Marker

On Android: please turn on "WebXR Incubations" in the Chrome Flags. You can find those by pasting chrome://flags/#webxr-incubations into the Chrome browser address bar of your Android phone.

',5)),s(t,{src:"https://engine.needle.tools/samples-uploads/image-tracking"}),i[4]||(i[4]=e("h3",{id:"interactive-building-blocks-overview",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#interactive-building-blocks-overview"},[e("span",null,"Interactive Building Blocks Overview")])],-1)),s(t,{src:"https://engine.needle.tools/samples-uploads/usdz-interactivity"}),i[5]||(i[5]=a(`

Create your own Everywhere Actions

Creating new Everywhere Actions involves writing code for your action in TypeScript, which will be used in the browser and for WebXR, and using our TriggerBuilder and ActionBuilder API to create a matching setup for Augmented Reality on iOS via QuickLook. When creating custom actions, keep in mind that QuickLook has a limited set of features available. You can still use any code you want for the browser and WebXR, but the behaviour for QuickLook may need to be an approximation built from the available triggers and actions.

Tips

Often constructing specific behaviours requires thinking outside the box and creatively applying the available low-level actions. An example would be a "Tap to Place" action โ€“ there is no raycasting or hit testing available in QuickLook, but you could cover the expected placement area with a number of invisible objects and use a "Tap" trigger to move the object to be placed to the position of the tapped invisible object.

Triggers and Actions for QuickLook are based on Apple's Preliminary Interactive USD Schemas

Code Example

Here's the implementation for HideOnStart as an example for how to create an Everywhere Action with implementations for both the browser and QuickLook:

import { Behaviour, UsdzBehaviour, BehaviorModel, TriggerBuilder, ActionBuilder, BehaviorExtension, USDObject, USDZExporterContext } from "@needle-tools/engine";
+
+export class HideOnStart extends Behaviour implements UsdzBehaviour {
+
+    start() {
+        this.gameObject.visible = false;
+    }
+
+    createBehaviours(ext: BehaviorExtension, model: USDObject, _context: USDZExporterContext) {
+        if (model.uuid === this.gameObject.uuid)
+            ext.addBehavior(new BehaviorModel("HideOnStart_" + this.gameObject.name,
+                TriggerBuilder.sceneStartTrigger(),
+                ActionBuilder.fadeAction(model, 0, false)
+            ));
+    }
+
+    beforeCreateDocument() {
+        this.gameObject.visible = true;
+    }
+
+    afterCreateDocument() {
+        this.gameObject.visible = false;
+    }
+}

Tips

Often, getting the right behaviour will involve composing higher-level actions from the available lower-level actions. For example, our "Change Material on Click" action is composed of a number of fadeActions and internally duplicates objects with different sets of materials each. By carefully constructing these actions, complex behaviours can be achieved.

Low level methods for building your own actions

Triggers
TriggerBuilder.sceneStartTrigger
TriggerBuilder.tapTrigger
Actions
ActionBuilder.fadeAction
ActionBuilder.startAnimationAction
ActionBuilder.waitAction
ActionBuilder.lookAtCameraAction
ActionBuilder.emphasize
ActionBuilder.transformAction
ActionBuilder.playAudioAction
Group Actions
ActionBuilder.sequence
ActionBuilder.parallel
GroupAction.addAction
GroupAction.makeParallel
GroupAction.makeSequence
GroupAction.makeLooping
GroupAction.makeRepeat

To see the implementation of our built-in Everywhere Actions, please take look at src/engine-components/export/usdz/extensions/behavior/BehaviourComponents.ts.

Further reading

The following pages provide more examples and samples that you can test and explore right now:

`,16))])}const g=n(d,[["render",p],["__file","everywhere-actions.html.vue"]]),y=JSON.parse(`{"path":"/everywhere-actions.html","title":"Everywhere Actions","lang":"en-US","frontmatter":{"title":"Everywhere Actions","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/everywhere actions.png"}],["meta",{"name":"og:description","content":"---\\nNeedle's Everywhere Actions are a set of carefully chosen components that allow you to create interactive experiences in Unity without writing a single line of code.\\nThey are designed to serve as building blocks for experiences across the web, mobile and XR, including Augmented Reality on iOS.\\nFrom low-level triggers and actions, higher-level complex interactive behaviours can be built."}]],"description":"---\\nNeedle's Everywhere Actions are a set of carefully chosen components that allow you to create interactive experiences in Unity without writing a single line of code.\\nThey are designed to serve as building blocks for experiences across the web, mobile and XR, including Augmented Reality on iOS.\\nFrom low-level triggers and actions, higher-level complex interactive behaviours can be built."},"headers":[{"level":2,"title":"What are Everywhere Actions?","slug":"what-are-everywhere-actions","link":"#what-are-everywhere-actions","children":[{"level":3,"title":"Supported Platforms","slug":"supported-platforms","link":"#supported-platforms","children":[]}]},{"level":2,"title":"How do I use Everywhere Actions?","slug":"how-do-i-use-everywhere-actions","link":"#how-do-i-use-everywhere-actions","children":[]},{"level":2,"title":"List of Everywhere Actions","slug":"list-of-everywhere-actions","link":"#list-of-everywhere-actions","children":[]},{"level":2,"title":"Samples","slug":"samples","link":"#samples","children":[{"level":3,"title":"Musical Instrument","slug":"musical-instrument","link":"#musical-instrument","children":[]},{"level":3,"title":"Simple Character Controllers","slug":"simple-character-controllers","link":"#simple-character-controllers","children":[]},{"level":3,"title":"Image Tracking","slug":"image-tracking","link":"#image-tracking","children":[]},{"level":3,"title":"Interactive Building Blocks Overview","slug":"interactive-building-blocks-overview","link":"#interactive-building-blocks-overview","children":[]}]},{"level":2,"title":"Create your own Everywhere Actions","slug":"create-your-own-everywhere-actions","link":"#create-your-own-everywhere-actions","children":[{"level":3,"title":"Code Example","slug":"code-example","link":"#code-example","children":[]},{"level":3,"title":"Low level methods for building your own actions","slug":"low-level-methods-for-building-your-own-actions","link":"#low-level-methods-for-building-your-own-actions","children":[]}]},{"level":2,"title":"Further reading","slug":"further-reading","link":"#further-reading","children":[]}],"git":{"updatedTime":1726585195000},"filePathRelative":"everywhere-actions.md"}`);export{g as comp,y as data}; diff --git a/assets/examples.html-BMSngmVr.js b/assets/examples.html-BMSngmVr.js new file mode 100644 index 000000000..16781c630 --- /dev/null +++ b/assets/examples.html-BMSngmVr.js @@ -0,0 +1 @@ +import{_ as o,r as s,o as l,c as i,e as d,b as r,a as e,d as a}from"./app-CRZRGfEE.js";const p={};function u(c,n){const t=s("video-embed");return l(),i("div",null,[n[0]||(n[0]=d('

Example Projects โœจ

Explore some real world applications, websites and demos made with Needle Engine.

Get started now โ€ข Learn more about our vision โ€ข Features Overview โ€ข Samples to download

Needle Website

Visit Website โ€” by Needle

',5)),r(t,{src:"https://user-images.githubusercontent.com/5083203/186126996-27b45c5f-f3b9-40f7-b8c7-6ecba1d25a6e.mp4"}),n[1]||(n[1]=e("h2",{id:"castle-builder",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#castle-builder"},[e("span",null,"Castle Builder")])],-1)),n[2]||(n[2]=e("p",null,[e("a",{href:"https://castle.needle.tools",target:"_blank",rel:"noopener noreferrer"},"Play Now"),a(" โ€” by Needle")],-1)),r(t,{src:"https://user-images.githubusercontent.com/5083203/186145731-705cfec2-1779-4a0b-97d9-95f3edaaf2d0.mp4"}),n[3]||(n[3]=e("h2",{id:"bike-configurator",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#bike-configurator"},[e("span",null,"Bike Configurator")])],-1)),n[4]||(n[4]=e("p",null,[e("a",{href:"https://bike.needle.tools",target:"_blank",rel:"noopener noreferrer"},"Bike Configurator"),a(" โ€” by Needle")],-1)),r(t,{src:"https://user-images.githubusercontent.com/5083203/186146814-52fb05c7-a073-4efa-a226-47a9c1835413.mp4"}),n[5]||(n[5]=e("h2",{id:"sandbox-template",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#sandbox-template"},[e("span",null,"Sandbox Template")])],-1)),n[6]||(n[6]=e("p",null,[e("a",{href:"https://fwd.needle.tools/needle-engine/glitch-starter",target:"_blank",rel:"noopener noreferrer"},"Sandbox Template"),a(" โ€” by Needle")],-1)),r(t,{src:"https://user-images.githubusercontent.com/5083203/186149117-ca7cf22f-dc7d-4c74-86d4-d78fe53a208c.mp4"}),n[7]||(n[7]=e("h2",{id:"songs-of-cultures",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#songs-of-cultures"},[e("span",null,"Songs of Cultures")])],-1)),n[8]||(n[8]=e("p",null,[e("a",{href:"https://fwd.needle.tools/needle-engine/projects/songs-of-cultures",target:"_blank",rel:"noopener noreferrer"},"Songs of Cultures"),a(" โ€” by A.MUSE")],-1)),r(t,{src:"https://user-images.githubusercontent.com/5083203/186147814-159a33f9-f1a6-47d4-804f-5f8f5a63125d.mp4"}),n[9]||(n[9]=e("h2",{id:"pok-mon-card",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#pok-mon-card"},[e("span",null,"Pokรฉmon Card")])],-1)),n[10]||(n[10]=e("p",null,[e("a",{href:"https://fwd.needle.tools/needle-engine/projects/pokemon-card",target:"_blank",rel:"noopener noreferrer"},"Pokรฉmon Card"),a(" โ€” Scene from Alex Ameye โ€ข "),e("a",{href:"https://alexanderameye.github.io/notes/holographic-card-shader/",target:"_blank",rel:"noopener noreferrer"},"Original Blog Post by Alex")],-1)),r(t,{src:"https://user-images.githubusercontent.com/5083203/186149736-49a697b3-4282-4b71-ab13-a6b176955c13.mp4"}),n[11]||(n[11]=e("h2",{id:"encryption-in-space",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#encryption-in-space"},[e("span",null,"Encryption in Space")])],-1)),n[12]||(n[12]=e("p",null,[e("a",{href:"https://fwd.needle.tools/needle-engine/projects/encryption",target:"_blank",rel:"noopener noreferrer"},"Encryption in Space"),a(" โ€” by Katja Rempel & Nick Jwu")],-1)),r(t,{src:"https://user-images.githubusercontent.com/5083203/186151157-0c0a7d05-ad42-44be-b553-8d4cd48cbb81.mp4"}),n[13]||(n[13]=e("h2",{id:"physics-playground",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#physics-playground"},[e("span",null,"Physics Playground")])],-1)),n[14]||(n[14]=e("p",null,[e("a",{href:"https://bruno-simon-20k-needle.glitch.me/",target:"_blank",rel:"noopener noreferrer"},"Physics Playground"),a(" โ€” Scene from Bruno Simon")],-1)),r(t,{src:"https://user-images.githubusercontent.com/5083203/186149536-987ee796-3fe0-42bc-bd80-4c25aaf174aa.mp4"})])}const m=o(p,[["render",u],["__file","examples.html.vue"]]),h=JSON.parse('{"path":"/examples.html","title":"Example Projects โœจ","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/examples.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[{"level":2,"title":"Needle Website","slug":"needle-website","link":"#needle-website","children":[]},{"level":2,"title":"Castle Builder","slug":"castle-builder","link":"#castle-builder","children":[]},{"level":2,"title":"Bike Configurator","slug":"bike-configurator","link":"#bike-configurator","children":[]},{"level":2,"title":"Sandbox Template","slug":"sandbox-template","link":"#sandbox-template","children":[]},{"level":2,"title":"Songs of Cultures","slug":"songs-of-cultures","link":"#songs-of-cultures","children":[]},{"level":2,"title":"Pokรฉmon Card","slug":"pok-mon-card","link":"#pok-mon-card","children":[]},{"level":2,"title":"Encryption in Space","slug":"encryption-in-space","link":"#encryption-in-space","children":[]},{"level":2,"title":"Physics Playground","slug":"physics-playground","link":"#physics-playground","children":[]}],"git":{"updatedTime":1726606065000},"filePathRelative":"examples.md"}');export{m as comp,h as data}; diff --git a/assets/export.html-Cyapuf2Z.js b/assets/export.html-Cyapuf2Z.js new file mode 100644 index 000000000..1a003d44e --- /dev/null +++ b/assets/export.html-Cyapuf2Z.js @@ -0,0 +1,23 @@ +import{_ as s,r as n,o,c as l,e as a,a as r,d as t,b as p,w as h}from"./app-CRZRGfEE.js";const d={};function c(g,e){const i=n("RouteLink");return o(),l("div",null,[e[3]||(e[3]=a('

Exporting Assets, Animations, Prefabs, Materials, Lightmaps...

Add an ExportInfo component to your Unity scene to generate a new web project from a template, link to an existing web project that you want to export to, set up dependencies to other libraries and packages and to deploy your project.

By default, your scene is exported on save. This setting can be changed by disabling Auto Export in the ExportInfo component.

๐Ÿ“ฆ Exporting glTF files

To export meshes, materials, animations, textures (...) create a new GameObject in your hierarchy and add a GltfObject component to it. This is the root of a new glTF file. It will be exported whenever you make a change to the scene and save.

Only scripts and data on and inside those root objects is exported. Scripts and data outside of them are not exported.

Add a cube as a child of your root object and save your scene. Note that the output assets/ folder (see project structure) now contains a new .glb file with the same name as your root GameObject.

You can enable the Smart Export setting (via Edit/Project Settings/Needle ) to only export when a change in this object's hierarchy is detected.

How to prevent specific objects from being exported

Objects with the EditorOnly tag will be ignored on export including their child hierarchy.
Be aware that this is preferred over disabling objects as disabled will still get exported in case they're turned on later.

Lazy loading and multiple levels / scenes

If you want to split up your application into multiple levels or scenes then you can simply use the SceneSwitcher component. You can then structure your application into multiple scenes or prefabs and add them to the SceneSwitcher array to be loaded and unloaded at runtime. This is a great way to avoid having to load all your content upfront and to keep loading times small (for example it is what we did on needle.tools by separating each section of your website into its own scene and only loading them when necessary)

  • Max. 50 MB export size uncompressed (usually ends up ~10-20 MB compressed)
  • Max. 500k vertices (less if you target mobile VR as well)
  • Max. 4x 2k lightmaps
',13)),r("p",null,[e[1]||(e[1]=t("You can split up scenes and prefabs into multiple glTF files, and then load those on demand (only when needed). This keeps loading performance fast and file size small. See the ")),p(i,{to:"/scripting.html#assetreference-and-addressables"},{default:h(()=>e[0]||(e[0]=[t("AssetReference section in the Scripting docs")])),_:1}),e[2]||(e[2]=t("."))]),e[4]||(e[4]=a(`

The scene complexity here is recommended to ensure good performance across a range of web-capable devices and bandwidths. There's no technical limitation to this beyond the capabilities of your device.

Prefabs

Prefabs can be exported as invidual glTF files and instantiated at runtime. To export a prefab as glTF just reference a prefab asset (from the project browser and not in the scene) from one of your scripts.

Exporting Prefabs works with nesting too: a component in a Prefab can reference another Prefab which will then also be exported.
This mechanism allows for composing scenes to be as lightweight as possible and loading the most important content first and defer loading of additional content.

Scene Assets

Similar to Prefab assets, you can reference other Scene assets.
To get started, create a component in Unity with a UnityEditor.SceneAsset field and add it to one of your GameObjects inside a GltfObject. The referenced scene will now be exported as a separate glTF file and can be loaded/deserialized as a AssetReference from TypeScript.

You can keep working inside a referenced scene and still update your main exporter scene/website. On scene save or play mode change we will detect if the current scene is being used by your currently running server and then trigger a re-export for only that glb. (This check is done by name - if a glb inside your <web_project>/assets/ folder exists, it is exported again and the main scene reloads it.)

As an example on our website each section is setup as a separate scene and on export packed into multiple glb files that we load on demand:

2022-08-22-172605_Needle_Website_-Website-_Windows,_Mac,Linux-_U

Loading a Prefab or Scene from a custom script

If you want to reference and load a prefab from one of your scripts you can declare a AssetReference type.
Here is a minimal example:

import { Behaviour, serializable, AssetReference } from "@needle-tools/engine";
+
+export class MyClass extends Behaviour {
+
+    // if you export a prefab or scene as a reference from Unity you'll get a path to that asset
+    // which you can de-serialize to AssetReference for convenient loading
+    @serializable(AssetReference)
+    myPrefab?: AssetReference;
+    
+    async start() {
+      // directly instantiate
+      const myInstance = await this.myPrefab?.instantiate();
+
+      // you can also just load and instantiate later
+      // const myInstance = await this.myPrefab.loadAssetAsync();
+      // this.gameObject.add(myInstance)
+      // this is useful if you know that you want to load this asset only once because it will not create a copy
+      // since \`\`instantiate()\`\` does create a copy of the asset after loading it
+    }  
+}

๐Ÿ‡ Exporting Animations

Needle Engine supports a considerable and powerful subset of Unity's animation features:

  • Timeline incl. activation tracks, animation tracks, track offsets
  • Animator incl. top-level state transitions
    • Blend trees are currently not supported.
    • Sub state machines are currently not supported.
  • AnimationClips incl. Loop modes
  • Procedural Animations can be created via scripting

Needle Engine is one of the first to support the new glTF extension KHR_ANIMATION_POINTER.
This means that almost all properties, including script variables, are animatable.

One current limitation is that materials won't be duplicated on export โ€” if you want to animate the same material with different colors, for example, you currently need to split the material in two.

๐ŸŒ Exporting the Skybox

The Unity skybox and custom reflection (if any) are baked into a texture on export and automatically exported inside the NEEDLE_lightmaps extension.

To change the skybox resolution you can add a SkyboxExportSettings component to your scene.

image

If you don't want to skybox to be exported at all in a glb file you can untick the Embed Skybox option on your GltfObject component

image

โœจ Exporting Materials

Physically Based Materials (PBR)

By default, materials are converted into glTF materials on export. glTF supports a physically based material model and has a number of extensions that help to represent complex materials.

For full control over what gets exported, it's highly recommended to use the glTF materials provided by UnityGltf:

  • PBRGraph
  • UnlitGraph

These materials are exported as-is, with no conversion necessary. They allow for using advanced material properties such as refractive transmission and iridescence, which can be exported as well.

Materials that can be converted out-of-the-box:

  • BiRP/Standard
  • BiRP/Autodesk Interactive
  • BiRP/Unlit
  • URP/Lit
  • URP/Unlit

Other materials are converted using a propery name heuristic. That means that depending on what property names your materials and shaders use, you might want to either refactor your custom shader's properties to use the property names of either URP/Lit or PBRGraph, or export the material as Custom Shader.

Custom Shaders

To export custom shaders (e.g. ShaderGraph shaders), add an ExportShader Asset Label (see bottom of the inspector) to the shader you want to export.

Warning

Please see limitations listed below

2022-08-22-172029_Needle_Website_-CustomShaders-_Windows,_Mac,_Lin

Note that Custom Shaders aren't part of the ratified glTF material model. The resulting GLB files will not display correctly in other viewers (the materials will most likely display white).

Current limitations

  • We currently only support custom Unlit shaders โ€” Lit shader conversion is not officially supported.
  • Custom Lit Shaders are currently experimental. Not all rendering modes are supported.
  • Shadow receiving on custom shaders is not supported
  • Skinned meshes with custom shaders are not supported
  • As there's multiple coordinate system changes when going from Unity to three.js and glTF, there might be some changes necessary to get advanced effects to work. We try to convert data on export but may not catch all cases where conversions are necessary.
    These coordinate changes are
    • UV coordinates in Unity start at the bottom left; in glTF they start at the top left.
    • X axis values are flipped in glTF compared to Unity (a variant of a left-handed to right-handed coordinate system change).

๐Ÿ’ก Exporting Lightmaps

2022-08-22-171650_Needle_-_Google_Chrome

To export lightmaps simply generate lightmaps in Unity. Lightmaps will be automatically exported.

When working on multiple scenes, disable "Auto Generate" and bake lightmaps explicitly. Otherwise, Unity will discard temporary lightmaps on scene change.

  • Lightmap Encoding: Normal Quality (adjust in Project Settings > Player)
  • Progressive GPU (faster and usually accurate enough for small scenes)
  • Non-Directional Lightmaps
  • Max Lightmap Size 2k (you can go higher, but expect large files)
  • Max 4x 2k lightmaps per scene (you can go higher, but expect large files)
  • Compress Lightmaps OFF (increases quality; otherwise will be compressed again at export time)

2022-08-22-171356_Needle_Website_-Lightmaps-_Windows,_Mac,Linux-

Mixing Baked and Non-Baked Objects

There's no 100% mapping between how Unity handles lights and environment and how three.js handle that. For example, Unity has entirely separate code paths for lightmapped and non-lightmapped objects (lightmapped objects don't receive ambient light since that is already baked into their maps), and three.js doesn't distinguish in that way.

This means that to get best results, we currently recommend specific settings if you're mixing baked and non-baked objects in a scene:

Environment Lighting: Skybox
+Ambient Intensity: 1
+Ambient Color: black

2021.3+
20220826-175324-SqBL-Unity_pMXa-needle

2020.3+
20220826-175514-tnGc-Unity_mycs-needle

If you have no baked objects in your scene, then the following settings should also yield correct results:

Environment Lighting: Color
+Ambient Color: any
`,54))])}const u=s(d,[["render",c],["__file","export.html.vue"]]),y=JSON.parse(`{"path":"/export.html","title":"Exporting Assets to glTF","lang":"en-US","frontmatter":{"title":"Exporting Assets to glTF","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/exporting assets to gltf.png"}],["meta",{"name":"og:description","content":"---\\nAdd an ExportInfo component to your Unity scene to generate a new web project from a template, link to an existing web project that you want to export to, set up dependencies to other libraries and packages and to deploy your project.\\nBy default, your scene is exported on save. This setting can be changed by disabling Auto Export in the ExportInfo component.\\nTo export meshes, materials, animations, textures (...) create a new GameObject in your hierarchy and add a GltfObject component to it. This is the root of a new glTF file. It will be exported whenever you make a change to the scene and save.\\nOnly scripts and data on and inside those root objects is exported. Scripts and data outside of them are not exported.\\nAdd a cube as a child of your root object and save your scene. Note that the output assets/ folder (see project structure) now contains a new .glb file with the same name as your root GameObject.\\nYou can enable the Smart Export setting (via Edit/Project Settings/Needle ) to only export when a change in this object's hierarchy is detected.\\n:::details How to prevent specific objects from being exported\\nObjects with the EditorOnly tag will be ignored on export including their child hierarchy.\\nBe aware that this is preferred over disabling objects as disabled will still get exported in case they're turned on later.\\n:::\\nIf you want to split up your application into multiple levels or scenes then you can simply use the SceneSwitcher component. You can then structure your application into multiple scenes or prefabs and add them to the SceneSwitcher array to be loaded and unloaded at runtime. This is a great way to avoid having to load all your content upfront and to keep loading times small (for example i"}]],"description":"---\\nAdd an ExportInfo component to your Unity scene to generate a new web project from a template, link to an existing web project that you want to export to, set up dependencies to other libraries and packages and to deploy your project.\\nBy default, your scene is exported on save. This setting can be changed by disabling Auto Export in the ExportInfo component.\\nTo export meshes, materials, animations, textures (...) create a new GameObject in your hierarchy and add a GltfObject component to it. This is the root of a new glTF file. It will be exported whenever you make a change to the scene and save.\\nOnly scripts and data on and inside those root objects is exported. Scripts and data outside of them are not exported.\\nAdd a cube as a child of your root object and save your scene. Note that the output assets/ folder (see project structure) now contains a new .glb file with the same name as your root GameObject.\\nYou can enable the Smart Export setting (via Edit/Project Settings/Needle ) to only export when a change in this object's hierarchy is detected.\\n:::details How to prevent specific objects from being exported\\nObjects with the EditorOnly tag will be ignored on export including their child hierarchy.\\nBe aware that this is preferred over disabling objects as disabled will still get exported in case they're turned on later.\\n:::\\nIf you want to split up your application into multiple levels or scenes then you can simply use the SceneSwitcher component. You can then structure your application into multiple scenes or prefabs and add them to the SceneSwitcher array to be loaded and unloaded at runtime. This is a great way to avoid having to load all your content upfront and to keep loading times small (for example i"},"headers":[{"level":2,"title":"๐Ÿ“ฆ Exporting glTF files","slug":"exporting-gltf-files","link":"#exporting-gltf-files","children":[{"level":3,"title":"Lazy loading and multiple levels / scenes","slug":"lazy-loading-and-multiple-levels-scenes","link":"#lazy-loading-and-multiple-levels-scenes","children":[]},{"level":3,"title":"Recommended Complexity per glTF","slug":"recommended-complexity-per-gltf","link":"#recommended-complexity-per-gltf","children":[]},{"level":3,"title":"Prefabs","slug":"prefabs","link":"#prefabs","children":[]},{"level":3,"title":"Scene Assets","slug":"scene-assets","link":"#scene-assets","children":[]}]},{"level":2,"title":"๐Ÿ‡ Exporting Animations","slug":"exporting-animations","link":"#exporting-animations","children":[]},{"level":2,"title":"๐ŸŒ Exporting the Skybox","slug":"exporting-the-skybox","link":"#exporting-the-skybox","children":[]},{"level":2,"title":"โœจ Exporting Materials","slug":"exporting-materials","link":"#exporting-materials","children":[{"level":3,"title":"Physically Based Materials (PBR)","slug":"physically-based-materials-pbr","link":"#physically-based-materials-pbr","children":[]},{"level":3,"title":"Custom Shaders","slug":"custom-shaders","link":"#custom-shaders","children":[]}]},{"level":2,"title":"๐Ÿ’ก Exporting Lightmaps","slug":"exporting-lightmaps","link":"#exporting-lightmaps","children":[{"level":3,"title":"Recommended Lightmap Settings","slug":"recommended-lightmap-settings","link":"#recommended-lightmap-settings","children":[]},{"level":3,"title":"Mixing Baked and Non-Baked Objects","slug":"mixing-baked-and-non-baked-objects","link":"#mixing-baked-and-non-baked-objects","children":[]}]}],"git":{"updatedTime":1726585195000},"filePathRelative":"export.md"}`);export{u as comp,y as data}; diff --git a/assets/faq.html-B6pZlv9Y.js b/assets/faq.html-B6pZlv9Y.js new file mode 100644 index 000000000..f81b3a1a1 --- /dev/null +++ b/assets/faq.html-B6pZlv9Y.js @@ -0,0 +1,11 @@ +import{_ as r}from"./ktx-env-variable-DxwKzzNo.js";import{_ as l,r as h,o as d,c,e as n,a as i,d as t,b as o,w as a}from"./app-CRZRGfEE.js";const p="/docs/imgs/unity-needle-engine-license.jpg",g="/docs/faq/lightmap_encoding.jpg",u={},k={class:"hint-container tip"};function m(f,e){const s=h("RouteLink");return d(),c("div",null,[e[14]||(e[14]=n('

I purchased a license - how can I activate my Needle Engine License?

Activating the license in Unity

Open Edit/Project Settings/Needle to get the Needle Engine plugin settings. At the top of the window you'll find fields for entering your license information.

  • Email - Enter the email you purchased the license with
  • Invoice ID - Enter one of the invoice ids that you received by email

unity license window

Activating the license in Blender

Open Addon Preferences/Needle Engine to get to the Needle Engine addon settings

  • Email - Enter the email you purchased the license with
  • Invoice ID - Enter one of the invoice ids that you received by email

My objects are white after export

This usually happens when you're using custom shaders or materials and their properties don't cleanly translate to known property names for glTF export.
You can either make sure you're using glTF-compatible materials and shaders, or mark shaders as "custom" to export them directly.

  • Read more about recommended glTF workflows:
  • Read more about custom shaders:

There's a SSL error when opening the local website

You might see a warning in your browser about SSL Security depending on your local configuration.

This is because while the connection is encrypted, by default there's no SSL certificate that the browser can validate. If that happens: click Advanced and Proceed to Site. In Safari, you might need to refresh the page afterwards, because it does not automatically proceed. Now you should see your scene in the browser!

The dialogue should only show up once for the same local server.

',15)),i("div",k,[e[3]||(e[3]=i("p",{class:"hint-container-title"},"Tips",-1)),e[4]||(e[4]=i("p",null,"Connections are secured, because we're enforcing HTTPS to make sure that WebXR and other modern web APIs work out-of-the-box. Some browsers will still complain that the SSL connection (between your local development server and the local website) can't be automatically trusted, and that you need to manually verify you trust that page. Automatic Page Reload and Websocket connections may also be affected depending on the browser and system settings.",-1)),i("p",null,[e[1]||(e[1]=t("See ")),o(s,{to:"/testing.html"},{default:a(()=>e[0]||(e[0]=[t("the Testing docs")])),_:1}),e[2]||(e[2]=t(" for information on how to set up a self-signed certificate for a smoother development experience."))])]),e[15]||(e[15]=n(`

My local website stays black

If that happens there's usually an exception either in engine code or your code. Open the dev tools (Ctrl + Shift + I or F12 in Chrome) and check the Console for errors.
In some cases, especially when you just updated the Needle Engine package version, this can be fixed by stopping and restarting the local dev server.
For that, click on the running progress bar in the bottom right corner of the Editor, and click the little X to cancel the running task. Then, simply press Play again.

How to fix Uncaught ReferenceError: NEEDLE_ENGINE_META is not defined / NEEDLE_USE_RAPIER is not defined

If you are using vite or next.js make sure to add the Needle Engine plugins to your config. Example for vite:

const { needlePlugins } = await import('@needle-tools/engine/plugins/vite/index.js');
+plugins: [needlePlugins(command, needleConfig)]

Example for next.js

const { needleNext } = await import("@needle-tools/engine/plugins/next/index.js");
+return needleNext({}, { modules: { webpack } });

You can also just declare the missing variables in e.g. your root index.html in a script tag like so:

<script>
+  var NEEDLE_ENGINE_META = {}
+  var NEEDLE_USE_RAPIER = true;
+</script>

THREE.EXRLoader: provided file doesnt appear to be in OpenEXR format

Please make sure that sure that you have set Lightmap Encoding to Normal Quality.
Go to Edit/Project Settings/Player for changing the setting.

My website becomes too large / is loading slow (too many MB)

This can have many reasons, but a few common ones are:

  • too many textures or textures are too large
  • meshes have too many vertices
  • meshes have vertex attributes you don't actually need (e.g. have normals and tangents but you're not using them)
  • objects are disabled and not ignored โ€“ disabled objects get exported as well in case you want to turn them on at runtime! Set their Tag to EditorOnly to completely ignore them for export.
  • you have multiple GltfObject components in your scene and they all have EmbedSkybox enabled (you need to have the skybox only once per scene you export)
',15)),i("p",null,[e[6]||(e[6]=t("If loading time itself is an issue you can ")),e[7]||(e[7]=i("strong",null,"try to split up your content into multiple glb files",-1)),e[8]||(e[8]=t(" and load them on-demand (this is what we do on our website). For it to work you can put your content into Prefabs or Scenes and reference them from any of your scripts. Please have a look at ")),o(s,{to:"/scripting.html#assetreference-and-addressables"},{default:a(()=>e[5]||(e[5]=[t("Scripting/Addressables in the documentation")])),_:1}),e[9]||(e[9]=t("."))]),e[16]||(e[16]=n('

My UI is not rendering Text

  • For Unity: Make sure that you use the UI/Legacy/Text component and not the TextMeshPro - Text component

My scripts don't work after export

  • Your existing C# code will not export as-is, you have to write matching typescript / javascript for it.
  • Needle uses typescript / javascript for components and generates C# stubs for them.
  • Components that already have matching JS will show that in the Inspector.

My lightmaps look different / too bright

Ensure you're following best practices for lightmaps and read about mixing baked and non-baked objects

My scene is too bright / lighting looks different than in Unity

Make sure that your lights are set to "Baked" or "Realtime". "Mixed" is currently not supported.

  • Lights set to mixed (with lightmapping) do affect objects twice in three.js, since there is currently no way to exclude lightmapped objects from lighting
  • The Intensity Multiplier factor for Skybox in Lighting/Environment is currently not supported and has no effect in Needle Engine
    image
  • Light shadow intensity can currently not be changed due to a three.js limitation.

Also see the docs on mixing baked and non-baked objects.

My skybox resolution is low? How to change my skybox resolution

  • If you use a custom cubemap: You can override the texture import settings of the skybox texture (assigned to your cubemap)

    image

  • If you use the default skybox: Add a SkyboxExportSettings component anywhere in your scene to override the default resolution

    image

My Shadows are not visible or cut off

Please the following points:

  • Your light has shadows enabled (either Soft Shadow or Hard Shadow)
  • Your objects are set to "Cast Shadows: On" (see MeshRenderer component)
  • For directional lights the position of the light is currently important since the shadow camera will be placed where the light is located in the scene.

My colors look wrong

Ensure your project is set to Linear colorspace.

image

I'm using networking and Glitch and it doesn't work if more than 30 people visit the Glitch page at the same time

  • Deploying on Glitch is a fast way to prototype and might even work for some small productions. The little server there doesn't have the power and bandwidth to host many people in a persistent session.
  • We're working on other networking ideas, but in the meantime you can host the website somewhere else (with node.js support) or simply remix it to distribute load among multiple servers. You can also host the networking backend package itself somewhere else where it can scale e.g. Google Cloud.

My website doesn't have AR/VR buttons

  • Make sure to add the WebXR component somewhere inside your root GltfObject.
  • Optionally add a AR Session Root component on your root GltfObject or within the child hierarchy to specify placement, scale and orientation for WebXR.
  • Optionally add a XR Rig component to control where users start in VR

I created a new script in a sub-scene but it does not work

When creating new scripts in npmdefs in sub-scenes (that is a scene that is exported as a reference from a script in your root export scene) you currently have to re-export the root scene again. This is because the code-gen that is responsible for registering new scripts currently only runs for scenes with a ExportInfo component. This will be fixed in the future.

My local server does not start / I do not see a website

The most likely reason is an incorrect installation. Check the console and the ExportInfo component for errors or warnings.

If these warnings/errors didn't help, try the following steps in order. Give them some time to complete. Stop once your problem has been resolved. Check the console for warnings and errors.

',27)),i("ul",null,[i("li",null,[e[11]||(e[11]=t("Make sure you follow the ")),o(s,{to:"/getting-started/#prerequisites"},{default:a(()=>e[10]||(e[10]=[t("Prerequisites")])),_:1}),e[12]||(e[12]=t("."))]),e[13]||(e[13]=n("
  • Install your project by selecting your ExportInfo component and clicking Install
  • Run a clean installation by selecting your ExportInfo component, holding Alt and clicking Clean Install
  • Try opening your web project directory in a command line tool and follow these steps:
    • run npm install and then npm run dev-host
    • Make sure both the local runtime package (node_modules/@needle-tools/engine) as well as three.js (node_modules/three) did install.
    • You may run npm install in both of these directories as well.
  • ",3))]),e[17]||(e[17]=n(`

    Does C# component generation work with javascript only too?

    While generating C# components does technically run with vanilla javascript too we don't recommend it and fully support it since it is more guesswork or simply impossible for the generator to know which C# type to create for your javascript class. Below you find a minimal example on how to generate a Unity Component from javascript if you really want to tho.

    class MyScript extends Behaviour
    +{
    +    //@type float
    +    myField = 5;
    +}

    I don't have any buttons like "Generate Project" in my components/inspector

    Please check that you're not accidentally in the Inspector's Debug mode โ€“ switch back to Normal:
    20220824-025011-S2GQ-Unity_lKlT-needle

    Toktx can not be found / toktx is not installed

    • Make sure to download and install toktx

    • On Windows: Make sure you have added toktx to your system environment variables. You may need to restart your computer after adding it to refresh the environment variables. The default install location is C:\\Program Files\\KTX-Software\\bin

    image

    Installing the web project takes forever / does never finish / EONET: no such file or directory

    • Make sure to not create a project on a drive formatted as exFAT because exFAT does not support symlinks, which is required for Needle Engine for Unity prior to version 3.x.
      You can check the formatting of your drives using the following steps:
      1. Open "System Information" (either windows key and type that or enter "msinfo32" in cmd)
      2. Select Components > Storage > Drives
      3. Select all (Ctrl + A) on the right side of the screen and copy that (Ctrl + C) and paste here (Ctrl + V)

    NPM install fails and there are errors about hard drive / IO

    Make sure your project is on a disk that is known to work with node.js. Main reason for failures is that the disk doesn't support symlinks (symbolic links / softlinks), which is a requirement for proper functioning of node.js.
    NTFS formatting should always work. Known problematic file system formattings are exFAT and FAT32.

    To check the format of your drives, you can:

    1. Open "System Information" (either Windows key and type "System Information" or enter msinfo32 in cmd Windows + R)
    2. Select "Components > Storage > Drives"
    3. There, you can see all drives and their formatting listed. Put your projects on a drive that is NTFS formatted.

    I'm getting errors with "Unexpected token @. Expected identifier, string literal, numeric literal or ..."

    Needle Engine uses typescript decorators for serialization.
    To fix this error make sure to enable experimentalDecorators in your tsconfig.json

    I'm getting an error 'failed to load config ... vite.config.js' when running npm commands on Mac OS

    You're likely using an x86_64 version of Unity on an (ARM) Apple Silicon processor. Unity 2020.3 is only available for x86_64, later versions also have Apple Silicon versions.
    Our Unity integration calling npm will thus do so from an x86_64 process, resulting in the x86_64 version of node and vite/esbuild being used. When you afterwards try to run npm commands in the same project from an Apple Silicon app (e.g. VS Code), npm will complain about mismatching architectures with a long error message.

    To fix this, use an Apple Silicon version of Unity (2021.1 or later).

    You can also temporarily fix it on 2020.3 by deleting the node_modules folder and running npm install again from VS Code. You'll have to delete node_modules again when you switch back to Unity.

    Circular reference error

    This can happen when you have e.g. a SceneSwitcher (or any other component that loads a scene or asset) and the referenced Asset in Unity contains a GltfObject that has the same name as your original scene with the SceneSwitcher. You can double check this in Unity if you get an error that says something like:

    Failed to export โ†‘ YourSceneName.glb
    +you seem to have objects with the same name referencing each other.

    To fix this you can:

    • Remove the GltfObject in the referenced Prefab or Scene
    • Rename the GameObject with the component that loads the referenced scenes

    If this doesn't fix the problem please ask in our discord.

    My scene is not loading and the console contains a warning with 'circular references' or 'failed to update active state'

    Please see the circular reference error section.

    Does my machine support WebGL 2?

    Use a detector like this one to determine if your device supports WebGL 2, it also hints at what could be the cause of your problem, but generally make sure you have updated your browser and drivers. WebGL 1 is not supported.

    Known devices to cause issues:

    • Lenovo Thinkpad - T495

    Still have questions? ๐Ÿ˜ฑ

    Ask in our friendly discord community

    `,35))])}const w=l(u,[["render",m],["__file","faq.html.vue"]]),v=JSON.parse(`{"path":"/faq.html","title":"Questions and Answers (FAQ) ๐Ÿ’ก","lang":"en-US","frontmatter":{"title":"Questions and Answers (FAQ) ๐Ÿ’ก","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/preview.jpeg"}],["meta",{"name":"og:description","content":"---"}]],"description":"---"},"headers":[{"level":2,"title":"I purchased a license - how can I activate my Needle Engine License?","slug":"i-purchased-a-license-how-can-i-activate-my-needle-engine-license","link":"#i-purchased-a-license-how-can-i-activate-my-needle-engine-license","children":[{"level":3,"title":"Activating the license in Unity","slug":"activating-the-license-in-unity","link":"#activating-the-license-in-unity","children":[]},{"level":3,"title":"Activating the license in Blender","slug":"activating-the-license-in-blender","link":"#activating-the-license-in-blender","children":[]}]},{"level":2,"title":"My objects are white after export","slug":"my-objects-are-white-after-export","link":"#my-objects-are-white-after-export","children":[]},{"level":2,"title":"There's a SSL error when opening the local website","slug":"there-s-a-ssl-error-when-opening-the-local-website","link":"#there-s-a-ssl-error-when-opening-the-local-website","children":[]},{"level":2,"title":"My local website stays black","slug":"my-local-website-stays-black","link":"#my-local-website-stays-black","children":[]},{"level":2,"title":"How to fix Uncaught ReferenceError: NEEDLE_ENGINE_META is not defined / NEEDLE_USE_RAPIER is not defined","slug":"how-to-fix-uncaught-referenceerror-needle-engine-meta-is-not-defined-needle-use-rapier-is-not-defined","link":"#how-to-fix-uncaught-referenceerror-needle-engine-meta-is-not-defined-needle-use-rapier-is-not-defined","children":[]},{"level":2,"title":"THREE.EXRLoader: provided file doesnt appear to be in OpenEXR format","slug":"three.exrloader-provided-file-doesnt-appear-to-be-in-openexr-format","link":"#three.exrloader-provided-file-doesnt-appear-to-be-in-openexr-format","children":[]},{"level":2,"title":"My website becomes too large / is loading slow (too many MB)","slug":"my-website-becomes-too-large-is-loading-slow-too-many-mb","link":"#my-website-becomes-too-large-is-loading-slow-too-many-mb","children":[]},{"level":2,"title":"My UI is not rendering Text","slug":"my-ui-is-not-rendering-text","link":"#my-ui-is-not-rendering-text","children":[]},{"level":2,"title":"My scripts don't work after export","slug":"my-scripts-don-t-work-after-export","link":"#my-scripts-don-t-work-after-export","children":[]},{"level":2,"title":"My lightmaps look different / too bright","slug":"my-lightmaps-look-different-too-bright","link":"#my-lightmaps-look-different-too-bright","children":[]},{"level":2,"title":"My scene is too bright / lighting looks different than in Unity","slug":"my-scene-is-too-bright-lighting-looks-different-than-in-unity","link":"#my-scene-is-too-bright-lighting-looks-different-than-in-unity","children":[]},{"level":2,"title":"My skybox resolution is low? How to change my skybox resolution","slug":"my-skybox-resolution-is-low-how-to-change-my-skybox-resolution","link":"#my-skybox-resolution-is-low-how-to-change-my-skybox-resolution","children":[]},{"level":2,"title":"My Shadows are not visible or cut off","slug":"my-shadows-are-not-visible-or-cut-off","link":"#my-shadows-are-not-visible-or-cut-off","children":[]},{"level":2,"title":"My colors look wrong","slug":"my-colors-look-wrong","link":"#my-colors-look-wrong","children":[]},{"level":2,"title":"I'm using networking and Glitch and it doesn't work if more than 30 people visit the Glitch page at the same time","slug":"i-m-using-networking-and-glitch-and-it-doesn-t-work-if-more-than-30-people-visit-the-glitch-page-at-the-same-time","link":"#i-m-using-networking-and-glitch-and-it-doesn-t-work-if-more-than-30-people-visit-the-glitch-page-at-the-same-time","children":[]},{"level":2,"title":"My website doesn't have AR/VR buttons","slug":"my-website-doesn-t-have-ar-vr-buttons","link":"#my-website-doesn-t-have-ar-vr-buttons","children":[]},{"level":2,"title":"I created a new script in a sub-scene but it does not work","slug":"i-created-a-new-script-in-a-sub-scene-but-it-does-not-work","link":"#i-created-a-new-script-in-a-sub-scene-but-it-does-not-work","children":[]},{"level":2,"title":"My local server does not start / I do not see a website","slug":"my-local-server-does-not-start-i-do-not-see-a-website","link":"#my-local-server-does-not-start-i-do-not-see-a-website","children":[]},{"level":2,"title":"Does C# component generation work with javascript only too?","slug":"does-c-component-generation-work-with-javascript-only-too","link":"#does-c-component-generation-work-with-javascript-only-too","children":[]},{"level":2,"title":"I don't have any buttons like \\"Generate Project\\" in my components/inspector","slug":"i-don-t-have-any-buttons-like-generate-project-in-my-components-inspector","link":"#i-don-t-have-any-buttons-like-generate-project-in-my-components-inspector","children":[]},{"level":2,"title":"Toktx can not be found / toktx is not installed","slug":"toktx-can-not-be-found-toktx-is-not-installed","link":"#toktx-can-not-be-found-toktx-is-not-installed","children":[]},{"level":2,"title":"Installing the web project takes forever / does never finish / EONET: no such file or directory","slug":"installing-the-web-project-takes-forever-does-never-finish-eonet-no-such-file-or-directory","link":"#installing-the-web-project-takes-forever-does-never-finish-eonet-no-such-file-or-directory","children":[]},{"level":2,"title":"NPM install fails and there are errors about hard drive / IO","slug":"npm-install-fails-and-there-are-errors-about-hard-drive-io","link":"#npm-install-fails-and-there-are-errors-about-hard-drive-io","children":[]},{"level":2,"title":"I'm getting errors with \\"Unexpected token @. Expected identifier, string literal, numeric literal or ...\\"","slug":"i-m-getting-errors-with-unexpected-token-.-expected-identifier-string-literal-numeric-literal-or-...","link":"#i-m-getting-errors-with-unexpected-token-.-expected-identifier-string-literal-numeric-literal-or-...","children":[]},{"level":2,"title":"I'm getting an error 'failed to load config ... vite.config.js' when running npm commands on Mac OS","slug":"i-m-getting-an-error-failed-to-load-config-...-vite.config.js-when-running-npm-commands-on-mac-os","link":"#i-m-getting-an-error-failed-to-load-config-...-vite.config.js-when-running-npm-commands-on-mac-os","children":[]},{"level":2,"title":"Circular reference error","slug":"circular-reference-error","link":"#circular-reference-error","children":[]},{"level":2,"title":"My scene is not loading and the console contains a warning with 'circular references' or 'failed to update active state'","slug":"my-scene-is-not-loading-and-the-console-contains-a-warning-with-circular-references-or-failed-to-update-active-state","link":"#my-scene-is-not-loading-and-the-console-contains-a-warning-with-circular-references-or-failed-to-update-active-state","children":[]},{"level":2,"title":"Does my machine support WebGL 2?","slug":"does-my-machine-support-webgl-2","link":"#does-my-machine-support-webgl-2","children":[]},{"level":2,"title":"Still have questions? ๐Ÿ˜ฑ","slug":"still-have-questions","link":"#still-have-questions","children":[]}],"git":{"updatedTime":1727125836000},"filePathRelative":"faq.md"}`);export{w as comp,v as data}; diff --git a/assets/features-overview.html-CBlEyL-B.js b/assets/features-overview.html-CBlEyL-B.js new file mode 100644 index 000000000..4f259ddfa --- /dev/null +++ b/assets/features-overview.html-CBlEyL-B.js @@ -0,0 +1 @@ +import{_ as p,r as a,o as u,c as m,a as t,d as n,b as o,w as r,e as d}from"./app-CRZRGfEE.js";const g={},f={class:"table-of-contents"};function b(h,e){const i=a("router-link"),l=a("RouteLink"),s=a("sample");return u(),m("div",null,[e[59]||(e[59]=t("h1",{id:"feature-overview",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#feature-overview"},[t("span",null,"Feature Overview")])],-1)),e[60]||(e[60]=t("p",null,[n("Needle Engine is a fully fledged 3D engine that runs in the browser. It comes with all the features you'd expect from a modern 3D engine, and more. If you haven't yet, take a look at our "),t("a",{href:"https://needle.tools",target:"_blank",rel:"noopener noreferrer"},"Homepage"),n(" and our "),t("a",{href:"https://engine.needle.tools/samples",target:"_blank",rel:"noopener noreferrer"},"Samples and Showcase"),n(".")],-1)),t("nav",f,[t("ul",null,[t("li",null,[o(i,{to:"#shaders-and-materials"},{default:r(()=>e[0]||(e[0]=[n("Shaders and Materials")])),_:1})]),t("li",null,[o(i,{to:"#crossplatform-vr-ar-mobile-desktop"},{default:r(()=>e[1]||(e[1]=[n("Crossplatform: VR, AR, Mobile, Desktop")])),_:1})]),t("li",null,[o(i,{to:"#lightmaps"},{default:r(()=>e[2]||(e[2]=[n("Lightmaps")])),_:1})]),t("li",null,[o(i,{to:"#multiplayer-and-networking"},{default:r(()=>e[3]||(e[3]=[n("Multiplayer and Networking")])),_:1})]),t("li",null,[o(i,{to:"#animations-and-sequencing"},{default:r(()=>e[4]||(e[4]=[n("Animations and Sequencing")])),_:1}),t("ul",null,[t("li",null,[o(i,{to:"#animator"},{default:r(()=>e[5]||(e[5]=[n("Animator")])),_:1})]),t("li",null,[o(i,{to:"#timeline"},{default:r(()=>e[6]||(e[6]=[n("Timeline")])),_:1})])])]),t("li",null,[o(i,{to:"#physics"},{default:r(()=>e[7]||(e[7]=[n("Physics")])),_:1})]),t("li",null,[o(i,{to:"#ui"},{default:r(()=>e[8]||(e[8]=[n("UI")])),_:1})]),t("li",null,[o(i,{to:"#particles"},{default:r(()=>e[9]||(e[9]=[n("Particles")])),_:1})]),t("li",null,[o(i,{to:"#postprocessing"},{default:r(()=>e[10]||(e[10]=[n("PostProcessing")])),_:1})]),t("li",null,[o(i,{to:"#editor-integrations"},{default:r(()=>e[11]||(e[11]=[n("Editor Integrations")])),_:1})]),t("li",null,[o(i,{to:"#scripting"},{default:r(()=>e[12]||(e[12]=[n("Scripting")])),_:1})]),t("li",null,[o(i,{to:"#and-there-is-more"},{default:r(()=>e[13]||(e[13]=[n("And there is more")])),_:1})])])]),e[61]||(e[61]=t("h2",{id:"shaders-and-materials",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#shaders-and-materials"},[t("span",null,"Shaders and Materials")])],-1)),e[62]||(e[62]=t("p",null,"Both PBR Materials and Custom shaders created with Shader Graph or other systems can be exported.",-1)),e[63]||(e[63]=t("img",{src:"https://user-images.githubusercontent.com/5083203/186012027-9bbe3944-fa56-41fa-bfbb-c989fa87aebb.png"},null,-1)),e[64]||(e[64]=t("p",null,[n("Use the node based "),t("a",{href:"https://unity.com/features/shader-graph",target:"_blank",rel:"noopener noreferrer"},"ShaderGraph"),n(" to create shaders for the web. ShaderGraph makes it easy for artists to keep creating without having to worry about syntax.")],-1)),t("p",null,[e[16]||(e[16]=n("Read more about ")),o(l,{to:"/export.html#physically-based-materials-pbr"},{default:r(()=>e[14]||(e[14]=[n("PBR Materials")])),_:1}),e[17]||(e[17]=n(" โ€ข ")),o(l,{to:"/export.html#custom-shaders"},{default:r(()=>e[15]||(e[15]=[n("Custom Shaders")])),_:1})]),e[65]||(e[65]=t("h2",{id:"crossplatform-vr-ar-mobile-desktop",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#crossplatform-vr-ar-mobile-desktop"},[t("span",null,"Crossplatform: VR, AR, Mobile, Desktop")])],-1)),t("p",null,[e[19]||(e[19]=n("Needle Engine runs everywhere web technology does: run the same application on desktop, mobile, AR or VR. We build Needle Engine ")),o(l,{to:"/xr.html"},{default:r(()=>e[18]||(e[18]=[n("with XR in mind")])),_:1}),e[20]||(e[20]=n(" and consider this as and integral part of responsive webdesign!"))]),t("p",null,[e[22]||(e[22]=n("Use ")),o(l,{to:"/everywhere-actions.html"},{default:r(()=>e[21]||(e[21]=[n("Everywhere Actions")])),_:1}),e[23]||(e[23]=n(" for ")),e[24]||(e[24]=t("strong",null,"Interactive AR on both Android and iOS",-1)),e[25]||(e[25]=n("."))]),e[66]||(e[66]=d('

    Lightmaps

    lightmaps

    Lightmaps can be baked in Unity or Blender to easily add beautiful static light to your 3d content. Lightbaking for the web was never as easy. Just mark objects that you want to lightmap as static in Unity, add one or many lights to your scene (or use emissive materials) and click bake. Needle Engine will export your lightmaps per scene and automatically load and display them just as you see it in the Editor!

    Note: There is no technical limitation on which lightmapper to use, as long as they end up in Unity's lightmapping data structures. Third party lightmappers such as Bakery thus are also supported.

    Multiplayer and Networking

    Networking is built into the core runtime. Needle Engine deployments to Glitch come with a tiny server that allows you to deploy a multiplayer 3D environment in seconds. The built-in networked components make it easy to get started, and you can create your own synchronized components. Synchronizing variables and state is super easy!

    Animations and Sequencing

    Needle Engine brings powerful animations, state control and sequencing to the web โ€” from just playing a single animation to orchestrating and blending complex animations and character controllers. The Exporter can translate Unity components like Animator and Timeline into a web-ready format.
    We even added this functionality to our Blender addon so you can craft compatible animation state machines and export nla tracks as timelines to the web from within Blender too.

    ',10)),t("ul",null,[t("li",null,[e[27]||(e[27]=n("Read more about ")),o(l,{to:"/component-reference.html#animation"},{default:r(()=>e[26]||(e[26]=[n("Animation Components")])),_:1})])]),e[67]||(e[67]=d('

    Animator

    The Animator and AnimatorController components in Unity let you setup animations and define conditions for when and how to blend between them. We support exporting state machines, StateMachineBehaviours, transitions and layers. StateMachineBehaviours are also supported with OnStateEnter, OnStateUpdate and OnStateExit events.

    Note: Sub-states and Blend Trees are not supported.

    Timeline

    2022-08-23-013517_Scene

    We're also translating Unity's Timeline setup and tracks into a web-ready format.
    Supported tracks include: AnimationTrack, AudioTrack, ActivationTrack, ControlTrack, SignalTrack.

    Note: Sub-Timelines are currently not supported.

    Note: It's possible to export custom timeline tracks.

    ',9)),t("ul",null,[t("li",null,[e[29]||(e[29]=n("Read more about ")),o(l,{to:"/component-reference.html#animation"},{default:r(()=>e[28]||(e[28]=[n("Animation Components")])),_:1})])]),e[68]||(e[68]=t("h2",{id:"physics",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#physics"},[t("span",null,"Physics")])],-1)),e[69]||(e[69]=t("p",null,"Use Rigidbodies, Mesh Colliders, Box Colliders and SphereColliders to add some juicy physics to your world.",-1)),t("ul",null,[t("li",null,[e[31]||(e[31]=n("Read more about ")),o(l,{to:"/component-reference.html#physics"},{default:r(()=>e[30]||(e[30]=[n("Physics Components")])),_:1})])]),o(s,{src:"https://engine.needle.tools/samples-uploads/physics-animation/"}),e[70]||(e[70]=t("h2",{id:"ui",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#ui"},[t("span",null,"UI")])],-1)),e[71]||(e[71]=t("p",null,"Building UI using Unity's UI canvas system is in development. Features currently include exporting Text (including fonts), Images, Buttons.",-1)),t("p",null,[e[33]||(e[33]=n("See the ")),o(l,{to:"/component-reference.html#ui"},{default:r(()=>e[32]||(e[32]=[n("ui component reference")])),_:1}),e[34]||(e[34]=n(" for supported component."))]),o(s,{src:"https://engine.needle.tools/samples-uploads/screenspace-ui"}),e[72]||(e[72]=t("h2",{id:"particles",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#particles"},[t("span",null,"Particles")])],-1)),e[73]||(e[73]=t("p",null,[n("Export of Unity ParticleSystem (Shuriken) is in development. Features currently include world/local space simulation, box and sphere emitter shapes, emission over time as well as burst emission, velocity- and color over time, emission by velocity, texturesheet animation, basic trails."),t("br"),n(" See a "),t("a",{href:"https://engine.needle.tools/samples/particles",target:"_blank",rel:"noopener noreferrer"},"live sample"),n(" of supported features below:")],-1)),o(s,{src:"https://engine.needle.tools/samples-uploads/particles/"}),e[74]||(e[74]=t("h2",{id:"postprocessing",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#postprocessing"},[t("span",null,"PostProcessing")])],-1)),t("p",null,[e[36]||(e[36]=n("Builtin effects include Bloom, Screenspace Ambient Occlusion, Depth of Field, Color Correction. You can also create your own custom effects. See ")),o(l,{to:"/component-reference.html#postprocessing"},{default:r(()=>e[35]||(e[35]=[n("the component reference")])),_:1}),e[37]||(e[37]=n(" for a complete list."))]),o(s,{src:"https://engine.needle.tools/samples-uploads/postprocessing/"}),e[75]||(e[75]=t("h2",{id:"editor-integrations",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#editor-integrations"},[t("span",null,"Editor Integrations")])],-1)),e[76]||(e[76]=t("p",null,[n("Needle Engine comes with powerful integrations into the Unity Editor and Blender."),t("br"),n(" It allows you to setup and export complex scenes in a visual way providing easy and flexible collaboration between artists and developers.")],-1)),e[77]||(e[77]=t("h2",{id:"scripting",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#scripting"},[t("span",null,"Scripting")])],-1)),t("p",null,[e[39]||(e[39]=n("Needle Engine uses as ")),o(l,{to:"/scripting.html#component-architecture"},{default:r(()=>e[38]||(e[38]=[n("component based workflow")])),_:1}),e[40]||(e[40]=n(". Create custom scripts in typescript or javascript. Use our ")),e[41]||(e[41]=t("a",{href:"https://fwd.needle.tools/needle-engine/docs/npmdef",target:"_blank",rel:"noopener noreferrer"},"modular npm-based package workflow",-1)),e[42]||(e[42]=n(" integrated into Unity. A ")),e[43]||(e[43]=t("a",{href:"https://fwd.needle.tools/needle-engine/docs/component-compiler",target:"_blank",rel:"noopener noreferrer"},"typescript to C# component compiler",-1)),e[44]||(e[44]=n(" produces Unity components magically on the fly."))]),e[78]||(e[78]=t("ul",null,[t("li",null,[n("Read more about "),t("a",{href:"scripting"},"Scripting Reference"),n(" โ€ข "),t("a",{href:"https://fwd.needle.tools/needle-engine/docs/npmdef",target:"_blank",rel:"noopener noreferrer"},"Npm Definition Files")])],-1)),e[79]||(e[79]=t("h2",{id:"and-there-is-more",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#and-there-is-more"},[t("span",null,"And there is more")])],-1)),t("ul",null,[e[48]||(e[48]=t("li",null,"PostProcessing โ†’ Bloom, Screenspace Ambient Occlusion, Depth of Field, Color Correction...",-1)),e[49]||(e[49]=t("li",null,"EditorSync โ†’ Live synchronize editing in Unity to the running three.js application for local development",-1)),t("li",null,[e[46]||(e[46]=n("Interactive AR on iOS and Android โ†’ Use our ")),o(l,{to:"/everywhere-actions.html"},{default:r(()=>e[45]||(e[45]=[n("Everywhere Actions")])),_:1}),e[47]||(e[47]=n(" feature set or build your own"))])]),e[80]||(e[80]=t("hr",null,null,-1)),e[81]||(e[81]=t("h1",{id:"where-to-go-next",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#where-to-go-next"},[t("span",null,"Where to go next")])],-1)),t("p",null,[e[51]||(e[51]=n("See our ")),o(l,{to:"/getting-started/"},{default:r(()=>e[50]||(e[50]=[n("Getting Started Guide")])),_:1}),e[52]||(e[52]=n(" to learn about how to download and set up Needle Engine.")),e[53]||(e[53]=t("br",null,null,-1)),e[54]||(e[54]=n(" Learn about ")),e[55]||(e[55]=t("a",{href:"vision"},"our vision",-1)),e[56]||(e[56]=n(" or dive deeper into some of the ")),e[57]||(e[57]=t("a",{href:"technical-overview"},"technical background and glTF",-1)),e[58]||(e[58]=n(" powering it all."))])])}const k=p(g,[["render",b],["__file","features-overview.html.vue"]]),w=JSON.parse('{"path":"/features-overview.html","title":"Feature Overview","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/features overview.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[{"level":2,"title":"Shaders and Materials","slug":"shaders-and-materials","link":"#shaders-and-materials","children":[]},{"level":2,"title":"Crossplatform: VR, AR, Mobile, Desktop","slug":"crossplatform-vr-ar-mobile-desktop","link":"#crossplatform-vr-ar-mobile-desktop","children":[]},{"level":2,"title":"Lightmaps","slug":"lightmaps","link":"#lightmaps","children":[]},{"level":2,"title":"Multiplayer and Networking","slug":"multiplayer-and-networking","link":"#multiplayer-and-networking","children":[]},{"level":2,"title":"Animations and Sequencing","slug":"animations-and-sequencing","link":"#animations-and-sequencing","children":[{"level":3,"title":"Animator","slug":"animator","link":"#animator","children":[]},{"level":3,"title":"Timeline","slug":"timeline","link":"#timeline","children":[]}]},{"level":2,"title":"Physics","slug":"physics","link":"#physics","children":[]},{"level":2,"title":"UI","slug":"ui","link":"#ui","children":[]},{"level":2,"title":"Particles","slug":"particles","link":"#particles","children":[]},{"level":2,"title":"PostProcessing","slug":"postprocessing","link":"#postprocessing","children":[]},{"level":2,"title":"Editor Integrations","slug":"editor-integrations","link":"#editor-integrations","children":[]},{"level":2,"title":"Scripting","slug":"scripting","link":"#scripting","children":[]},{"level":2,"title":"And there is more","slug":"and-there-is-more","link":"#and-there-is-more","children":[]}],"git":{"updatedTime":1727125836000},"filePathRelative":"features-overview.md"}');export{k as comp,w as data}; diff --git a/assets/for-unity-developers.html-9HXvx0qv.js b/assets/for-unity-developers.html-9HXvx0qv.js new file mode 100644 index 000000000..2a695bad9 --- /dev/null +++ b/assets/for-unity-developers.html-9HXvx0qv.js @@ -0,0 +1,122 @@ +import{_ as p,r as h,o as r,c as o,e as l,a as s,d as e,b as t,w as n}from"./app-CRZRGfEE.js";const d={},c={class:"hint-container details"};function g(y,i){const a=h("RouteLink"),k=h("video-embed");return r(),o("div",null,[i[41]||(i[41]=l('

    Needle Engine provides a tight integration into the Unity Editor. This allows developers and designers alike to work together in a familiar environment and deliver fast, performant and lightweight web-experiences.

    The following guide is mainly aimed at developers with a Unity3D background but it may also be useful for developers with a web or three.js background. It covers topics regarding how things are done in Unity vs in three.js or Needle Engine.

    If you are all new to Typescript and Javascript and you want to dive into writing scripts for Needle Engine then we also recommend reading the Typescript Essentials Guide for a basic understanding between the differences between C# and Javascript/Typescript.

    If you want to code-along you can open engine.needle.tools/new to create a small project that you can edit in the browser โšก

    The Basics

    Needle Engine is a 3d web engine running on-top of three.js. Three.js is one of the most popular 3D webgl based rendering libraries for the web. Whenever we refer to a gameObject in Needle Engine we are actually also talking about a three.js Object3D, the base type of any object in three.js. Both terms can be used interchangeably. Any gameObject is a Object3D.

    This also means that - if you are already familiar with three.js - you will have no problem at all using Needle Engine. Everything you can do with three.js can be done in Needle Engine as well. If you are already using certain libraries then you will be able to also use them in a Needle Engine based environment.

    ',7)),s("p",null,[i[1]||(i[1]=e("Note: ")),i[2]||(i[2]=s("strong",null,[e("Needle Engine's Exporter does "),s("em",null,"NOT"),e(" compile your existing C# code to Web Assembly")],-1)),i[3]||(i[3]=e(".")),i[4]||(i[4]=s("br",null,null,-1)),i[5]||(i[5]=e(" While using Web Assembly ")),i[6]||(i[6]=s("em",null,"may",-1)),i[7]||(i[7]=e(" result in better performance at runtime, it comes at a high cost for iteration speed and flexibility in building web experiences. Read more about our ")),t(a,{to:"/getting-started/vision.html"},{default:n(()=>i[0]||(i[0]=[e("vision")])),_:1}),i[8]||(i[8]=e(" and ")),i[9]||(i[9]=s("a",{href:"./technical-overview"},"technical overview",-1)),i[10]||(i[10]=e("."))]),s("details",c,[i[11]||(i[11]=s("summary",null,"How to create a new Unity project with Needle Engine? (Video)",-1)),t(k,{src:"https://www.youtube.com/watch?v=gZX_sqrne8U",limit_height:""})]),i[42]||(i[42]=l(`

    Creating a Component

    In Unity you create a new component by deriving from MonoBehaviour:

    using UnityEngine;
    +public class MyComponent : MonoBehaviour { 
    +}

    A custom component in Needle Engine on the other hand is written as follows:

    import { Behaviour } from "@needle-tools/engine"
    +export class MyComponent extends Behaviour { 
    +}

    Script Fields

    serializable

    If you have seen some Needle Engine scripts then you might have noticed that some variables are annotated with @serializable above their declaration. This is a Decorator in Typescript and can be used to modify or annotate code. In Needle Engine this is used for example to let the core serialization know which types we expect in our script when it converts from the raw component information stored in the glTF to a Component instance.
    Consider the following example:

    import { Behaviour, serializable } from "@needle-tools/engine";
    +import { Object3D } from "three";
    +
    +class SomeClass extends Behaviour{
    +    @serializable(Behaviour)
    +    myOtherComponent?: Behaviour;
    +    @serializable(Object3D)
    +    someOtherObject?: Object3D;
    +}

    This tells Needle Engine that myOtherComponent should be of type Behaviour. It will then automatically assign the correct reference to the field when your scene is loaded. The same is true for someOtherObject where we want to deserialize to an Object3D reference.

    Note that in some cases the type can be ommitted. This can be done for all primitive types in Javascript. These are boolean, number, bigint, string, null and undefined.

    import { Behaviour, serializable } from "@needle-tools/engine";
    +class SomeClass {
    +    @serializable() // < no type is needed here because the field type is a primitive
    +    myString?: string;
    +}

    public vs private

    Field without any accessor modified like private, public or protected will by default be public in javascript

    import { Behaviour, serializable } from "@needle-tools/engine";
    +class SomeClass {
    +    /// no accessor means it is public:
    +    myNumber?: number;
    +    // explicitly making it private:
    +    private myPrivateNumber?: number;
    +    protected myProtectedNumber?: number;
    +}

    The same is true for methods as well.

    GameObjects and the Scene

    To access the current scene from a component you use this.scene which is equivalent to this.context.scene, this gives you the root three.js scene object.

    To traverse the hierarchy from a component you can either iterate over the children of an object
    with a for loop:

    for (let i = 0; i < this.gameObject.children; i++) {
    +    console.log(this.gameObject.children[i]);
    +}

    or you can iterate using the foreach equivalent:

    for (const child of this.gameObject.children) {
    +    console.log(child);
    +}

    You can also use three.js specific methods to quickly iterate all objects recursively using the traverse method:

    import { GameObject } from "@needle-tools/engine";
    +//---cut-before---
    +this.gameObject.traverse((obj: GameObject) => console.log(obj))

    or to just traverse visible objects use traverseVisible instead.

    Another option that is quite useful when you just want to iterate objects being renderable you can query all renderer components and iterate over them like so:

    import { Renderer } from "@needle-tools/engine";
    +
    +for(const renderer of this.gameObject.getComponentsInChildren(Renderer))
    +    console.log(renderer);

    For more information about getting components see the next section.

    Components

    `,29)),s("p",null,[i[13]||(i[13]=e("Needle Engine is making heavy use of a Component System that is similar to that of Unity. This means that you can add or remove components to any ")),i[14]||(i[14]=s("code",null,"Object3D",-1)),i[15]||(i[15]=e(" / ")),i[16]||(i[16]=s("code",null,"GameObject",-1)),i[17]||(i[17]=e(" in the scene. A component will be registered to the engine when using ")),i[18]||(i[18]=s("code",null,"addNewComponent(, )",-1)),i[19]||(i[19]=e(".")),i[20]||(i[20]=s("br",null,null,-1)),i[21]||(i[21]=e(" The event methods that the attached component will then automatically be called by the engine (e.g. ")),i[22]||(i[22]=s("code",null,"update",-1)),i[23]||(i[23]=e(" or ")),i[24]||(i[24]=s("code",null,"onBeforeRender",-1)),i[25]||(i[25]=e("). A full list of event methods can be found in the ")),t(a,{to:"/scripting.html#lifecycle-methods"},{default:n(()=>i[12]||(i[12]=[e("scripting documentation")])),_:1})]),i[43]||(i[43]=l('

    Finding Components in the Scene

    For getting component you can use the familiar methods similar to Unity. Note that the following uses the Animator type as an example but you can as well use any component type that is either built-in or created by you.

    Method nameDesciption
    this.gameObject.getComponent(Animator)Get the Animator component on a GameObject/Object3D. It will either return the Animator instance if it has an Animator component or null if the object has no such componnent.
    this.gameObject.getComponentInChildren(Animator)Get the first Animator component on a GameObject/Object3D or on any of its children
    this.gameObject.getComponentsInParents(Animator)Get all animator components in the parent hierarchy (including the current GameObject/Object3D)

    These methods are also available on the static GameObject type. For example GameObject.getComponent(this.gameObject, Animator) to get the Animator component on a passed in GameObject/Object3D.

    To search the whole scene for one or multiple components you can use GameObject.findObjectOfType(Animator) or GameObject.findObjectsOfType(Animator).

    Renamed Unity Types

    Some Unity-specific types are mapped to different type names in our engine. See the following list:

    Type in UnityType in Needle Engine
    UnityEventEventListA UnityEvent will be exported as a EventList type (use serializable(EventList) to deserialize UnityEvents)
    GameObjectObject3D
    TransformObject3DIn three.js and Needle Engine a GameObject and a Transform are the same (there is no Transform component). The only exception to that rule is when referencing a RectTransform which is a component in Needle Engine as well.
    ColorRGBAColorThe three.js color type doesnt have a alpha property. Because of that all Color types exported from Unity will be exported as RGBAColor which is a custom Needle Engine type

    Transform

    Transform data can be accessed on the GameObject / Object3D directly. Unlike to Unity there is no extra transform component that holds this data.

    • this.gameObject.position is the position in local space
    • this.gameObject.rotation is the rotation in euler angles in local space
    • this.gameObject.quaternion - is the quaternion in local space
    • this.gameObject.scale - is the scale in local space

    The major difference here to keep in mind is that position in three.js is by default a localspace position whereas in Unity position would be worldspace. The next section will explain how to get the worldspace position in three.js.

    WORLD- Position, Rotation, Scale...

    In three.js (and thus also in Needle Engine) the object.position, object.rotation, object.scale are all local space coordinates. This is different to Unity where we are used to position being worldspace and using localPosition to deliberately use the local space position.

    If you want to access the world coordinates in Needle Engine we have utility methods that you can use with your objects. Call getWorldPosition(yourObject) to calculate the world position. Similar methods exist for rotation/quaternion and scale. To get access to those methods just import them from Needle Engine like so import { getWorldPosition } from "@needle.tools/engine"

    ',15)),s("p",null,[i[27]||(i[27]=e("Note that these utility methods like ")),i[28]||(i[28]=s("code",null,"getWorldPosition",-1)),i[29]||(i[29]=e(", ")),i[30]||(i[30]=s("code",null,"getWorldRotation",-1)),i[31]||(i[31]=e(", ")),i[32]||(i[32]=s("code",null,"getWorldScale",-1)),i[33]||(i[33]=e(" internally have a buffer of Vector3 instances and are meant to be used locally only. This means that you should not cache them in your component, otherwise your cached value will eventually be overriden. But it is safe to call ")),i[34]||(i[34]=s("code",null,"getWorldPosition",-1)),i[35]||(i[35]=e(" multiple times in your function to make calculations without having to worry to re-use the same instance. If you are not sure what this means you should take a look at the ")),i[36]||(i[36]=s("strong",null,"Primitive Types",-1)),i[37]||(i[37]=e(" section in the ")),t(a,{to:"/getting-started/typescript-essentials.html#primitive-types"},{default:n(()=>i[26]||(i[26]=[e("Typescript Essentials Guide")])),_:1})]),i[44]||(i[44]=l(`

    Time

    Use this.context.time to get access to time data:

    • this.context.time.time is the time since the application started running
    • this.context.time.deltaTime is the time that has passed since the last frame
    • this.context.time.frameCount is the number of frames that have passed since the application started
    • this.context.time.realtimeSinceStartup is the unscaled time since the application has started running

    It is also possible to use this.context.time.timeScale to deliberately slow down time for e.g. slow motion effects.

    Raycasting

    Use this.context.physics.raycast() to perform a raycast and get a list of intersections. If you dont pass in any options the raycast is performed from the mouse position (or first touch position) in screenspace using the currently active mainCamera. You can also pass in a RaycastOptions object that has various settings like maxDistance, the camera to be used or the layers to be tested against.

    Use this.context.physics.raycastFromRay(your_ray) to perform a raycast using a three.js ray

    Note that the calls above are by default raycasting against visible scene objects. That is different to Unity where you always need colliders to hit objects. The default three.js solution has both pros and cons where one major con is that it can perform quite slow depending on your scene geometry. It may be especially slow when raycasting against skinned meshes. It is therefor recommended to usually set objects with SkinnedMeshRenderers in Unity to the Ignore Raycast layer which will then be ignored by default by Needle Engine as well.

    Another option is to use the physics raycast methods which will only return hits with colliders in the scene.

    const hit = this.context.physics.engine?.raycast();

    Here is a editable example for physics raycast

    Input

    Use this.context.input to poll input state:

    import { Behaviour } from "@needle-tools/engine";
    +export class MyScript extends Behaviour
    +{
    +    update(){
    +        if(this.context.input.getPointerDown(0)){
    +            console.log("POINTER DOWN")
    +        }
    +    }
    +}

    You can also subscribe to events in the InputEvents enum like so:

    import { Behaviour, InputEvents, NEPointerEvent } from "@needle-tools/engine";
    +
    +export class MyScript extends Behaviour
    +{
    +    onEnable(){
    +        this.context.input.addEventListener(InputEvents.PointerDown, this.inputPointerDown);
    +    }
    +    onDisable() {
    +        // it is recommended to also unsubscribe from events when your component becomes inactive
    +        this.context.input.removeEventListener(InputEvents.PointerDown, this.inputPointerDown);
    +    }
    +
    +    inputPointerDown = (evt: NEPointerEvent) => { console.log(evt); }
    +}

    If you want to handle inputs yourself you can also subscribe to all events the browser provides (there are a ton). For example to subscribe to the browsers click event you can write:

    window.addEventListener("click", () => { console.log("MOUSE CLICK"); });

    Note that in this case you have to handle all cases yourself. For example you may need to use different events if your user is visiting your website on desktop vs mobile vs a VR device. These cases are automatically handled by the Needle Engine input events (e.g. PointerDown is raised both for mouse down, touch down and in case of VR on controller button down).

    InputSystem Callbacks

    Similar to Unity (see IPointerClickHandler in Unity) you can also register to receive input events on the component itself.

    To make this work make sure your object has a ObjectRaycaster or GraphicRaycaster component in the parent hierarchy.

    import { Behaviour, IPointerEventHandler, PointerEventData } from "@needle-tools/engine";
    +
    +export class ReceiveClickEvent extends Behaviour implements IPointerEventHandler {
    +    onPointerClick(args: PointerEventData) {
    +        console.log("Click", args);
    +    }
    +}

    Note: IPointerEventHandler subscribes the object to all possible pointer events. The handlers for them are:

    • onPointerDown
    • onPointerUp
    • onPointerEnter
    • onPointerMove
    • onPointerExit
    • onPointerClick

    All have a PointerEventData argument describing the event.

    Debug.Log

    The Debug.Log() equivalent in javascript is console.log(). You can also use console.warn() or console.error().

    import { GameObject, Renderer } from "@needle-tools/engine";
    +const someVariable = 42;
    +// ---cut-before---
    +
    +console.log("Hello web");
    +// You can pass in as many arguments as you want like so:
    +console.log("Hello", someVariable, GameObject.findObjectOfType(Renderer), this.context);

    Gizmos

    In Unity you normally have to use special methods to draw Gizmos like OnDrawGizmos or OnDrawGizmosSelected. In Needle Engine on the other hand such methods dont exist and you are free to draw gizmos from anywhere in your script. Note that it is also your responsibility then to not draw them in e.g. your deployed web application (you can just filter them by if(isDevEnvironment))).

    Here is an example to draw a red wire sphere for one second for e.g. visualizing a point in worldspace

    import { Vector3 } from "three";
    +const hit = { point: new Vector3(0, 0, 0) };
    +// ---cut-before---
    +import { Gizmos } from "@needle-tools/engine";
    +Gizmos.DrawWireSphere(hit.point, 0.05, 0xff0000, 1);

    Here are some of the available gizmo methods:

    Method name
    Gizmos.DrawArrow
    Gizmos.DrawBox
    Gizmos.DrawBox3
    Gizmos.DrawDirection
    Gizmos.DrawLine
    Gizmos.DrawRay
    Gizmos.DrawRay
    Gizmos.DrawSphere
    Gizmos.DrawWireSphere

    Useful Utility Methods

    Import from @needle-tools/engine e.g. import { getParam } from "@needle-tools/engine"

    Method nameDescription
    getParam()Checks if a url parameter exists. Returns true if it exists but has no value (e.g. ?help), false if it is not found in the url or is set to 0 (e.g. ?help=0), otherwise it returns the value (e.g. ?message=test)
    isMobileDevice()Returns true if the app is accessed from a mobile device
    isDevEnvironment()Returns true if the current app is running on a local server
    isMozillaXR()
    isiOS
    isSafari
    import { isMobileDevice } from "@needle-tools/engine"
    +if( isMobileDevice() )
    import { getParam } from "@needle-tools/engine"
    +// returns true 
    +const myFlag = getParam("some_flag")
    +console.log(myFlag)

    The Web project

    In C# you usually work with a solution containing one or many projects. In Unity this solution is managed by Unity for you and when you open a C# script it opens the project and shows you the file.
    You usually install Packages using Unity's built-in package manager to add features provided by either Unity or other developers (either on your team or e.g. via Unity's AssetStore). Unity does a great job of making adding and managing packages easy with their PackageManager and you might never have had to manually edit a file like the manifest.json (this is what Unity uses to track which packages are installed) or run a command from the command line to install a package.

    In a web environment you use npm - the Node Package Manager - to manage dependencies / packages for you. It does basically the same to what Unity's PackageManager does - it installs (downloads) packages from some server (you hear it usually called a registry in that context) and puts them inside a folder named node_modules.

    When working with a web project most of you dependencies are installed from npmjs.com. It is the most popular package registry out there for web projects.

    Here is an example of how a package.json might look like:

    {
    +  "name": "@optional_org/package_name",
    +  "version": "1.0.0",
    +  "scripts": {
    +    "start": "vite --host"
    +  },
    +  "dependencies": {
    +	  "@needle-tools/engine": "^3.5.9-beta",
    +	  "three": "npm:@needle-tools/three@0.146.8"
    +	},
    +  "devDependencies": {
    +	  "@types/three": "0.146.0",
    +	  "@vitejs/plugin-basic-ssl": "^1.0.1",
    +	  "typescript": "^5.0.4",
    +	  "vite": "^4.3.4",
    +	  "vite-plugin-compression": "^0.5.1"
    +	}
    +}

    Our default template uses Vite as its bundler and has no frontend framework pre-installed. Needle Engine is unoppionated about which framework to use so you are free to work with whatever framework you like. We have samples for popular frameworks like Vue.js, Svelte, Next.js, React or React Three Fiber.

    Installing packages & dependencies

    To install a dependency from npm you can open your web project in a commandline (or terminal) and run npm i <the/package_name> (shorthand for npm install)
    For example run npm i @needle-tools/engine to install Needle Engine. This will then add the package to your package.json to the dependencies array.
    To install a package as a devDependency only you can run npm i --save-dev <package_name>. More about the difference between dependencies and devDependencies below.

    What's the difference between 'dependencies' and 'devDependencies'

    You may have noticed that there are two entries containing dependency - dependencies and devDependencies.

    dependencies are always installed (or bundled) when either your web project is installed or in cases where you develop a library and your package is installed as a dependency of another project.

    devDependencies are only installed when developing the project (meaning that when you directly run install in the specific directory) and they are otherwise not included in your project.

    How do I install another package or dependency and how to use it?

    The Installing section taught us that you can install dependencies by running npm i <package_name> in your project directory where the package_name can be any package that you find on npm.js.

    Let's assume you want to add a tweening library to your project. We will use @tweenjs/tween.js for this example. Here is the final project if you want to jump ahead and just see the result.

    First run npm install @tweenjs/tween.js in the terminal and wait for the installation to finish. This will add a new entry to our package.json:

    "dependencies": {
    +    "@needle-tools/engine": "^3.5.11-beta",
    +    "@tweenjs/tween.js": "^20.0.3",
    +    "three": "npm:@needle-tools/three@0.146.8"
    +}

    Then open one of your script files in which you want to use tweening and import at the top of the file:

    import * as TWEEN from '@tweenjs/tween.js';

    Note that we do here import all types in the library by writing * as TWEEN. We could also just import specific types like import { Tween } from @tweenjs/tween.js.

    Now we can use it in our script. It is always recommended to refer to the documentation of the library that you want to use. In the case of tween.js they provide a user guide that we can follow. Usually the Readme page of the package on npm contains information on how to install and use the package.

    To rotate a cube we create a new component type called TweenRotation, we then go ahead and create our tween instance for the object rotation, how often it should repeat, which easing to use, the tween we want to perform and then we start it. We then only have to call update every frame to update the tween animation. The final script looks like this:

    import { Behaviour } from "@needle-tools/engine";
    +import * as TWEEN from '@tweenjs/tween.js';
    +
    +export class TweenRotation extends Behaviour {
    +
    +    // save the instance of our tweener
    +    private _tween?: TWEEN.Tween<any>; 
    +
    +    start() {
    +        const rotation = this.gameObject.rotation;
    +        // create the tween instance
    +        this._tween = new TWEEN.Tween(rotation);
    +        // set it to repeat forever
    +        this._tween.repeat(Infinity);
    +        // set the easing to use
    +        this._tween.easing(TWEEN.Easing.Quintic.InOut);
    +        // set the values to tween
    +        this._tween.to({ y: Math.PI * 0.5 }, 1000);
    +        // start it
    +        this._tween.start();
    +    }
    +    
    +    update() {
    +        // update the tweening every frame
    +        // the '?' is a shorthand for checking if _tween has been created
    +        this._tween?.update();
    +    }
    +}

    Now we only have to add it to any of the objects in our scene to rotate them forever.
    You can see the final script in action here.

    Learning more

    `,66)),s("ul",null,[i[40]||(i[40]=s("li",null,[s("a",{href:"../scripting"},"Scripting in Needle Engine")],-1)),s("li",null,[t(a,{to:"/getting-started/typescript-essentials.html"},{default:n(()=>i[38]||(i[38]=[e("Typescript Essentials")])),_:1})]),s("li",null,[t(a,{to:"/component-reference.html"},{default:n(()=>i[39]||(i[39]=[e("Component Reference")])),_:1})])])])}const F=p(d,[["render",g],["__file","for-unity-developers.html.vue"]]),u=JSON.parse(`{"path":"/getting-started/for-unity-developers.html","title":"Scripting Introduction for Unity Developers","lang":"en-US","frontmatter":{"title":"Scripting Introduction for Unity Developers","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/scripting introduction for unity developers.png"}],["meta",{"name":"og:description","content":"---\\nNeedle Engine provides a tight integration into the Unity Editor. This allows developers and designers alike to work together in a familiar environment and deliver fast, performant and lightweight web-experiences.\\nThe following guide is mainly aimed at developers with a Unity3D background but it may also be useful for developers with a web or three.js background. It covers topics regarding how things are done in Unity vs in three.js or Needle Engine.\\nIf you are all new to Typescript and Javascript and you want to dive into writing scripts for Needle Engine then we also recommend reading the Typescript Essentials Guide for a basic understanding between the differences between Cand Javascript/Typescript.\\nIf you want to code-along you can open engine.needle.tools/new to create a small project that you can edit in the browser โšก\\nNeedle Engine is a 3d web engine running on-top of three.js. Three.js is one of the most popular 3D webgl based rendering libraries for the web. Whenever we refer to a gameObject in Needle Engine we are actually also talking about a three.js Object3D, the base type of any object in three.js. Both terms can be used interchangeably. Any gameObject is a Object3D.\\nThis also means that"}]],"description":"---\\nNeedle Engine provides a tight integration into the Unity Editor. This allows developers and designers alike to work together in a familiar environment and deliver fast, performant and lightweight web-experiences.\\nThe following guide is mainly aimed at developers with a Unity3D background but it may also be useful for developers with a web or three.js background. It covers topics regarding how things are done in Unity vs in three.js or Needle Engine.\\nIf you are all new to Typescript and Javascript and you want to dive into writing scripts for Needle Engine then we also recommend reading the Typescript Essentials Guide for a basic understanding between the differences between Cand Javascript/Typescript.\\nIf you want to code-along you can open engine.needle.tools/new to create a small project that you can edit in the browser โšก\\nNeedle Engine is a 3d web engine running on-top of three.js. Three.js is one of the most popular 3D webgl based rendering libraries for the web. Whenever we refer to a gameObject in Needle Engine we are actually also talking about a three.js Object3D, the base type of any object in three.js. Both terms can be used interchangeably. Any gameObject is a Object3D.\\nThis also means that"},"headers":[{"level":2,"title":"The Basics","slug":"the-basics","link":"#the-basics","children":[]},{"level":2,"title":"Creating a Component","slug":"creating-a-component","link":"#creating-a-component","children":[]},{"level":2,"title":"Script Fields","slug":"script-fields","link":"#script-fields","children":[{"level":3,"title":"serializable","slug":"serializable","link":"#serializable","children":[]},{"level":3,"title":"public vs private","slug":"public-vs-private","link":"#public-vs-private","children":[]}]},{"level":2,"title":"GameObjects and the Scene","slug":"gameobjects-and-the-scene","link":"#gameobjects-and-the-scene","children":[]},{"level":2,"title":"Components","slug":"components","link":"#components","children":[]},{"level":2,"title":"Renamed Unity Types","slug":"renamed-unity-types","link":"#renamed-unity-types","children":[]},{"level":2,"title":"Transform","slug":"transform","link":"#transform","children":[{"level":3,"title":"WORLD- Position, Rotation, Scale...","slug":"world-position-rotation-scale...","link":"#world-position-rotation-scale...","children":[]}]},{"level":2,"title":"Time","slug":"time","link":"#time","children":[]},{"level":2,"title":"Raycasting","slug":"raycasting","link":"#raycasting","children":[]},{"level":2,"title":"Input","slug":"input","link":"#input","children":[]},{"level":2,"title":"InputSystem Callbacks","slug":"inputsystem-callbacks","link":"#inputsystem-callbacks","children":[]},{"level":2,"title":"Debug.Log","slug":"debug.log","link":"#debug.log","children":[]},{"level":2,"title":"Gizmos","slug":"gizmos","link":"#gizmos","children":[]},{"level":2,"title":"Useful Utility Methods","slug":"useful-utility-methods","link":"#useful-utility-methods","children":[]},{"level":2,"title":"The Web project","slug":"the-web-project","link":"#the-web-project","children":[]},{"level":2,"title":"Installing packages & dependencies","slug":"installing-packages-dependencies","link":"#installing-packages-dependencies","children":[{"level":3,"title":"What's the difference between 'dependencies' and 'devDependencies'","slug":"what-s-the-difference-between-dependencies-and-devdependencies","link":"#what-s-the-difference-between-dependencies-and-devdependencies","children":[]},{"level":3,"title":"How do I install another package or dependency and how to use it?","slug":"how-do-i-install-another-package-or-dependency-and-how-to-use-it","link":"#how-do-i-install-another-package-or-dependency-and-how-to-use-it","children":[]}]}],"git":{"updatedTime":1726585195000},"filePathRelative":"getting-started/for-unity-developers.md"}`);export{F as comp,u as data}; diff --git a/assets/for-unity-developers.html-Cn4ckO1w.js b/assets/for-unity-developers.html-Cn4ckO1w.js new file mode 100644 index 000000000..258bc5ca4 --- /dev/null +++ b/assets/for-unity-developers.html-Cn4ckO1w.js @@ -0,0 +1 @@ +import{_ as n,o as a,c as o,a as e,d as r}from"./app-CRZRGfEE.js";const s={};function i(d,t){return a(),o("div",null,t[0]||(t[0]=[e("h1",{id:"this-page-has-been-moved-continue-here",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#this-page-has-been-moved-continue-here"},[e("span",null,[r("This page has been moved: "),e("a",{href:"./getting-started/for-unity-developers"},"continue here")])])],-1)]))}const c=n(s,[["render",i],["__file","for-unity-developers.html.vue"]]),p=JSON.parse('{"path":"/for-unity-developers.html","title":"Scripting basics For Unity Developers","lang":"en-US","frontmatter":{"title":"Scripting basics For Unity Developers","editLinks":false,"sidebar":false,"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/preview.jpeg"}],["meta",{"name":"og:description","content":"---"}]],"description":"---"},"headers":[],"git":{"updatedTime":1725399379000},"filePathRelative":"for-unity-developers.md"}');export{c as comp,p as data}; diff --git a/assets/getting-started.html-CpSyGMSg.js b/assets/getting-started.html-CpSyGMSg.js new file mode 100644 index 000000000..45cfc47b7 --- /dev/null +++ b/assets/getting-started.html-CpSyGMSg.js @@ -0,0 +1 @@ +import{_ as a,r as o,o as r,c as s,a as i,d as e,b as d,w as g}from"./app-CRZRGfEE.js";const l={};function m(c,t){const n=o("RouteLink");return r(),s("div",null,[i("p",null,[t[1]||(t[1]=e("Moved to ")),d(n,{to:"/getting-started/"},{default:g(()=>t[0]||(t[0]=[e("Getting Started")])),_:1})])])}const _=a(l,[["render",m],["__file","getting-started.html.vue"]]),f=JSON.parse('{"path":"/getting-started.html","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/getting started.png"}],["meta",{"name":"og:description","content":")"}]],"description":")"},"headers":[],"git":{"updatedTime":1727125836000},"filePathRelative":"getting-started.md"}');export{_ as comp,f as data}; diff --git a/assets/github-star-DNJWumWy.js b/assets/github-star-DNJWumWy.js new file mode 100644 index 000000000..bbe11bd3c --- /dev/null +++ b/assets/github-star-DNJWumWy.js @@ -0,0 +1 @@ +import{h as r,i as a,j as n,k as l,l as h,_ as u,r as d,o as p,m as c,w as f,d as _}from"./app-CRZRGfEE.js";const $=r({name:"github-button",props:{href:String,ariaLabel:String,title:String,dataIcon:String,dataColorScheme:String,dataSize:String,dataShowCount:String,dataText:String},render:function(){const t={ref:"_"};for(const e in this.$props)t[a(e)]=this.$props[e];return n("span",[l(this.$slots,"default")?n("a",t,this.$slots.default()):n("a",t)])},mounted:function(){this.paint()},beforeUpdate:function(){this.reset()},updated:function(){this.paint()},beforeUnmount:function(){this.reset()},methods:{paint:function(){if(this.$el.lastChild!==this.$refs._)return;const t=this.$el.appendChild(document.createElement("span")),e=this;h(()=>import("./buttons.esm-CUWjhgaJ.js"),[]).then(function(i){e.$el.lastChild===t&&i.render(t.appendChild(e.$refs._),function(o){e.$el.lastChild===t&&t.parentNode.replaceChild(o,t)})})},reset:function(){this.$refs._!=null&&this.$el.replaceChild(this.$refs._,this.$el.lastChild)}}}),g={components:{GithubButton:$}};function m(t,e,i,o,b,S){const s=d("github-button");return p(),c(s,{href:"https://github.com/needle-tools/needle-engine-support","data-icon":"octicon-star","data-size":"large","data-show-count":"true","aria-label":"Star needle-tools/needle-engine-support on GitHub"},{default:f(()=>e[0]||(e[0]=[_("Star")])),_:1})}const x=u(g,[["render",m],["__file","github-star.vue"]]);export{x as default}; diff --git a/assets/html.html-DP7Dz9Ne.js b/assets/html.html-DP7Dz9Ne.js new file mode 100644 index 000000000..16133abd7 --- /dev/null +++ b/assets/html.html-DP7Dz9Ne.js @@ -0,0 +1,35 @@ +import{_ as o}from"./custom-loading-style-s1K1my2z.js";import{_ as p,r,o as h,c as d,e as l,a as i,d as s,b as t,w as n}from"./app-CRZRGfEE.js";const k="/docs/imgs/unity-needle-engine-modules-physics.jpg",c={},g={class:"hint-container tip"};function u(y,e){const a=r("RouteLink");return h(),d("div",null,[e[24]||(e[24]=l('

    Bundling and web frontends

    Needle Engine is build as a web component.
    This means just install @needle-tools/engine in your project and include <needle-engine src="path/to/your.glb"> anywhere in your web-project.

    • Install using npm:
      npm i @needle-tools/engine

    With our default Vite based project template Needle Engine gets bundled into a web app on deployment. This ensures smaller files, tree-shaking (similar to code stripping in Unity) and optimizes load times. Instead of downloading numerous small scripts and components, only one or a few are downloaded that contain the minimal code needed.

    Vite (our default bundler) has a good explanation why web apps should be bundled: Why Bundle for Production

    Vite, Vue, React, Svelte, React Three Fiber...

    Needle Engine is unoponiated about the choice of framework. Our default template uses the popular vite as bundler. From there, you can add vue, svelte, nuxt, react, react-three-fiber or other frameworks, and we have samples for a lot of them. You can also integrate other bundlers, or use none at all โ€“ just plain HTML and Javascript.

    Here's some example tech stacks that are possible and that we use Needle Engine with:

    ',8)),i("ul",null,[e[3]||(e[3]=l('
  • Vite + HTML โ€” This is what our default template uses!

  • Vite + Vue โ€” This is what the Needle Tools website uses!. Find a sample to download here.

  • Vite + Svelte

  • Vite + SvelteKit

  • Vite + React โ€” There's an experimental template shipped with the Unity integration for this that you can pick when generating a project!

  • react-three-fiber โ€” There's an experimental template shipped with the Unity integration for this that you can pick when generating a project!

  • Vercel & Nextjs โ€” Find a example nextjs project here

  • ',7)),i("li",null,[i("p",null,[e[1]||(e[1]=i("strong",null,"CDN without any bundler",-1)),e[2]||(e[2]=s(" โ€” Find a code example ")),t(a,{to:"/vanilla-js.html"},{default:n(()=>e[0]||(e[0]=[s("here")])),_:1})])])]),e[25]||(e[25]=i("p",null,[s("In short: we're currently providing a minimal vite template, but you can extend it or switch to other frameworks โ€“"),i("br"),s(" Let us know what and how you build, and how we can improve the experience for your usecase or provide an example!")],-1)),i("div",g,[e[11]||(e[11]=i("p",{class:"hint-container-title"},"Tips",-1)),i("p",null,[e[5]||(e[5]=s("Some frameworks require custom settings in ")),e[6]||(e[6]=i("code",null,"needle.config.json",-1)),e[7]||(e[7]=s(". Learn more ")),t(a,{to:"/reference/needle-config-json.html"},{default:n(()=>e[4]||(e[4]=[s("here")])),_:1}),e[8]||(e[8]=s(". Typically, the ")),e[9]||(e[9]=i("code",null,"baseUrl",-1)),e[10]||(e[10]=s(" needs to be set."))])]),e[26]||(e[26]=l(`
    How do I create a custom project template in Unity?

    You can create and share your own web project templates to use other bundlers, build systems, or none at all.

    Create a new Template

    1. Select Create/Needle Engine/Project Template to add a ProjectTemplate into the folder you want to use as a template
    2. Done! It's that simple.

    The dependencies come from unity when there is a NpmDef in the project (so when your project uses local references).
    You could also publish your packages to npm and reference them via version number.

    Tree-shaking to reduce bundle size

    Tree shaking refers to a common practice when it comes to bundling of web applications (see MSDN docs). It means that code paths and features that are not used in your code will be removed from the final bundled javascript file(s) to reduce filesize. See below about features that Needle Engine includes and remove them:

    How to remove Rapier physics engine? (Reduce the overall bundle size removing ~2MB (~600KB when gzipping))
    • Option 1: via needlePlugins config:
      Set useRapier to false in your vite.config: needlePlugins(command, needleConfig, { useRapier: false }),

    • Option 2: via vite.define config:
      Declare the NEEDLE_USE_RAPIER define with false

      define: {
      +  NEEDLE_USE_RAPIER: false
      +},
    • Option 3: via .env
      Create a .env file in your web project and add VITE_NEEDLE_USE_RAPIER=false

    • Option 4: via Unity component
      Add the Needle Engine Modules component to your scene and set Physics Engine to None

    Creating a PWA

    We support easily creating a Progressive Web App (PWA) directly from our vite template.
    PWAs are web applications that load like regular web pages or websites but can offer user functionality such as working offline, push notifications, and device hardware access traditionally available only to native mobile applications.

    By default, PWAs created with Needle have offline support, and can optionally refresh automatically when you publish a new version of your app.

    1. Install the Vite PWA plugin in your web project: npm install vite-plugin-pwa --save-dev
    2. Modify vite.config.js as seen below. Make sure to pass the same pwaOptions object to both needlePlugins and VitePWA.
    import { VitePWA } from 'vite-plugin-pwa';
    +
    +export default defineConfig(async ({ command }) => {
    +
    +    // Create the pwaOptions object. 
    +    // You can edit or enter PWA settings here (e.g. change the PWA name or add icons).
    +    /** @type {import("vite-plugin-pwa").VitePWAOptions} */
    +    const pwaOptions = {};
    +  
    +    const { needlePlugins } = await import("@needle-tools/engine/plugins/vite/index.js");
    +
    +    return {
    +        plugins: [
    +            // pass the pwaOptions object to the needlePlugins and the VitePWA function
    +            needlePlugins(command, needleConfig, { pwa: pwaOptions }),
    +            VitePWA(pwaOptions),
    +        ],
    +        // the rest of your vite config...

    All assets are cached by default

    Note that by default, all assets in your build folder are added the PWA precache โ€“ for large applications with many dynamic assets, this may not be what you want (imagine the YouTube PWA caching all videos once a user opens the app!). See More PWA Options for how to customize this behavior.

    Testing PWAs

    To test your PWA, deploy the page, for example using the DeployToFTP component.
    Then, open the deployed page in a browser and check if the PWA features work as expected:

    • the app shows up as installable
    • the app works offline
    • the app is detected as offline-capable PWA by pwabuilder.com

    PWAs use Service Workers to cache resources and provide offline support. Service Workers are somewhat harder to use during development, and typically are only enabled for builds (e.g. when you use a DeployTo... component).

    You can enable PWA support for development by adding the following to the options object in your vite.config.js.

    const pwaOptions = {
    +  // Note: PWAs behave different in dev mode. 
    +  // Make sure to verify the behaviour in production builds!
    +  devOptions: {
    +    enabled: true,
    +  }
    +};

    Please note that PWAs in development mode do not support offline usage โ€“ trying it may result in unexpected behavior.

    Automatically update running apps

    Websites typically show new or updated content on page refresh.

    In some situations, you may want the page to refresh and reload automatically when a new version has been published โ€“ such as in a museum, trade show, public display, or other long-running scenarios.

    To enable automatic updates, set the updateInterval property in the pwaOptions object to a duration (in milliseconds) in which the app should check for updates. If an update is detected, the page will reload automatically.

    const pwaOptions = {
    +  updateInterval: 15 * 60 * 1000, // 15 minutes, in milliseconds
    +};

    Periodic Reloads and User Data

    It's not recommended to use automatic reloads in applications where users are interacting with forms or other data that could be lost on a reload. For these applications, showing a reload prompt is recommended.
    See the Vite PWA plugin documentation for more information on how to implement a reload prompt instead of automatic reloading.

    More PWA options

    Since Needle uses the Vite PWA plugin under the hood, you can use all options and hooks provided by that.
    For example, you can provide a partial manifest with a custom app title or theme color:

    const pwaOptions = {
    +  // manifest options provided here will override the defaults 
    +  manifest: {
    +    name: "My App",
    +    short_name: "My App",
    +    theme_color: "#B2D464",
    +  }
    +};

    For complex requirements like partial caching, custom service workers or different update strategies, you can remove the { pwa: pwaOptions } option from needlePlugins and add PWA functionality directly through the Vite PWA plugin.

    Accessing Needle Engine and Components from external javascript

    `,28)),i("p",null,[e[13]||(e[13]=s("Code that you expose can be accessed from JavaScript after bundling. This allows to build viewers and other applications where there's a split between data known at edit time and data only known at runtime (e.g. dynamically loaded files, user generated content).")),e[14]||(e[14]=i("br",null,null,-1)),e[15]||(e[15]=s(" For accessing components from regular javascript outside of the engine please refer to the ")),t(a,{to:"/scripting.html#accessing-needle-engine-and-components-from-anywhere"},{default:n(()=>e[12]||(e[12]=[s("interop with regular javascript section")])),_:1})]),e[27]||(e[27]=i("h2",{id:"customizing-how-loading-looks",tabindex:"-1"},[i("a",{class:"header-anchor",href:"#customizing-how-loading-looks"},[i("span",null,"Customizing how loading looks")])],-1)),i("p",null,[e[17]||(e[17]=s("See the ")),e[18]||(e[18]=i("em",null,"Loading Display",-1)),e[19]||(e[19]=s(" section in ")),t(a,{to:"/reference/needle-engine-attributes.html"},{default:n(()=>e[16]||(e[16]=[s("needle engine component reference")])),_:1})]),e[28]||(e[28]=l('

    Builtin styles

    The needle-engine loading appearance can use a light or dark skin.
    To change the appearance use the loading-style attribute on the <needle-engine> web component.
    Options are light and dark (default):

    <needle-engine loading-style="light"></needle-engine>

    Custom Loading Style โ€” PRO feature

    ',4)),i("p",null,[e[21]||(e[21]=s("Please see the ")),e[22]||(e[22]=i("em",null,"Loading Display",-1)),e[23]||(e[23]=s(" section in ")),t(a,{to:"/reference/needle-engine-attributes.html"},{default:n(()=>e[20]||(e[20]=[s("needle engine component reference")])),_:1})]),e[29]||(e[29]=i("p",null,[i("img",{src:o,alt:"custom loading"})],-1))])}const C=p(c,[["render",u],["__file","html.html.vue"]]),b=JSON.parse('{"path":"/html.html","title":"Frameworks, Bundlers, HTML","lang":"en-US","frontmatter":{"title":"Frameworks, Bundlers, HTML","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/frameworks, bundlers, html.png"}],["meta",{"name":"og:description","content":"---\\nNeedle Engine is build as a web component.\\nThis means just install @needle-tools/engine in your project and include anywhere in your web-project."}]],"description":"---\\nNeedle Engine is build as a web component.\\nThis means just install @needle-tools/engine in your project and include anywhere in your web-project."},"headers":[{"level":2,"title":"Bundling and web frontends","slug":"bundling-and-web-frontends","link":"#bundling-and-web-frontends","children":[{"level":3,"title":"Vite, Vue, React, Svelte, React Three Fiber...","slug":"vite-vue-react-svelte-react-three-fiber...","link":"#vite-vue-react-svelte-react-three-fiber...","children":[]},{"level":3,"title":"Tree-shaking to reduce bundle size","slug":"tree-shaking-to-reduce-bundle-size","link":"#tree-shaking-to-reduce-bundle-size","children":[]}]},{"level":2,"title":"Creating a PWA","slug":"creating-a-pwa","link":"#creating-a-pwa","children":[{"level":3,"title":"Testing PWAs","slug":"testing-pwas","link":"#testing-pwas","children":[]},{"level":3,"title":"Automatically update running apps","slug":"automatically-update-running-apps","link":"#automatically-update-running-apps","children":[]},{"level":3,"title":"More PWA options","slug":"more-pwa-options","link":"#more-pwa-options","children":[]}]},{"level":2,"title":"Accessing Needle Engine and Components from external javascript","slug":"accessing-needle-engine-and-components-from-external-javascript","link":"#accessing-needle-engine-and-components-from-external-javascript","children":[]},{"level":2,"title":"Customizing how loading looks","slug":"customizing-how-loading-looks","link":"#customizing-how-loading-looks","children":[{"level":3,"title":"Builtin styles","slug":"builtin-styles","link":"#builtin-styles","children":[]},{"level":3,"title":"Custom Loading Style โ€” PRO feature","slug":"custom-loading-style-pro-feature","link":"#custom-loading-style-pro-feature","children":[]}]}],"git":{"updatedTime":1725399379000},"filePathRelative":"html.md"}');export{C as comp,b as data}; diff --git a/assets/index-DWGeGWcS.js b/assets/index-DWGeGWcS.js new file mode 100644 index 000000000..d7c66ac0d --- /dev/null +++ b/assets/index-DWGeGWcS.js @@ -0,0 +1,14 @@ +/*! @docsearch/js 3.6.1 | MIT License | ยฉ Algolia, Inc. and contributors | https://docsearch.algolia.com */function on(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter(function(o){return Object.getOwnPropertyDescriptor(t,o).enumerable})),n.push.apply(n,r)}return n}function N(t){for(var e=1;et.length)&&(e=t.length);for(var n=0,r=new Array(e);n3)for(n=[n],i=3;i0?Ue(d.type,d.props,d.key,null,d.__v):d)!=null){if(d.__=n,d.__b=n.__b+1,(y=g[a])===null||y&&d.key==y.key&&d.type===y.type)g[a]=void 0;else for(h=0;h<_;h++){if((y=g[h])&&d.key==y.key&&d.type===y.type){g[h]=void 0;break}y=null}Qt(t,d,y=y||Et,o,i,u,s,l,f),v=d.__e,(h=d.ref)&&y.ref!=h&&(m||(m=[]),y.ref&&m.push(y.ref,null,d),m.push(h,d.__c||v,d)),v!=null?(p==null&&(p=v),typeof d.type=="function"&&d.__k!=null&&d.__k===y.__k?d.__d=l=vr(d,l,t):l=dr(t,d,y,g,v,l),f||n.type!=="option"?typeof n.type=="function"&&(n.__d=l):t.value=""):l&&y.__e==l&&l.parentNode!=t&&(l=nt(y))}for(n.__e=p,a=_;a--;)g[a]!=null&&(typeof n.type=="function"&&g[a].__e!=null&&g[a].__e==n.__d&&(n.__d=nt(r,a+1)),gr(g[a],g[a]));if(m)for(a=0;a3)for(n=[n],i=3;i=n.__.length&&n.__.push({}),n.__[t]}function Gt(t){return Ce=1,br(Sr,t)}function br(t,e,n){var r=it(xe++,2);return r.t=t,r.__c||(r.__=[n?n(e):Sr(void 0,e),function(o){var i=r.t(r.__[0],o);r.__[0]!==i&&(r.__=[i,r.__[1]],r.__c.setState({}))}],r.__c=K),r.__}function Yt(t,e){var n=it(xe++,3);!j.__s&&Xt(n.__H,e)&&(n.__=t,n.__H=e,K.__H.__h.push(n))}function hn(t,e){var n=it(xe++,4);!j.__s&&Xt(n.__H,e)&&(n.__=t,n.__H=e,K.__h.push(n))}function Ct(t,e){var n=it(xe++,7);return Xt(n.__H,e)&&(n.__=t(),n.__H=e,n.__h=t),n.__}function eo(){Ft.forEach(function(t){if(t.__P)try{t.__H.__h.forEach(bt),t.__H.__h.forEach(Bt),t.__H.__h=[]}catch(e){t.__H.__h=[],j.__e(e,t.__v)}}),Ft=[]}j.__b=function(t){K=null,fn&&fn(t)},j.__r=function(t){mn&&mn(t),xe=0;var e=(K=t.__c).__H;e&&(e.__h.forEach(bt),e.__h.forEach(Bt),e.__h=[])},j.diffed=function(t){pn&&pn(t);var e=t.__c;e&&e.__H&&e.__H.__h.length&&(Ft.push(e)!==1&&sn===j.requestAnimationFrame||((sn=j.requestAnimationFrame)||function(n){var r,o=function(){clearTimeout(i),yn&&cancelAnimationFrame(r),setTimeout(n)},i=setTimeout(o,100);yn&&(r=requestAnimationFrame(o))})(eo)),K=void 0},j.__c=function(t,e){e.some(function(n){try{n.__h.forEach(bt),n.__h=n.__h.filter(function(r){return!r.__||Bt(r)})}catch(r){e.some(function(o){o.__h&&(o.__h=[])}),e=[],j.__e(r,n.__v)}}),vn&&vn(t,e)},j.unmount=function(t){dn&&dn(t);var e=t.__c;if(e&&e.__H)try{e.__H.__.forEach(bt)}catch(n){j.__e(n,e.__v)}};var yn=typeof requestAnimationFrame=="function";function bt(t){var e=K;typeof t.__c=="function"&&t.__c(),K=e}function Bt(t){var e=K;t.__c=t.__(),K=e}function Xt(t,e){return!t||t.length!==e.length||e.some(function(n,r){return n!==t[r]})}function Sr(t,e){return typeof e=="function"?e(t):e}function Or(t,e){for(var n in e)t[n]=e[n];return t}function Vt(t,e){for(var n in t)if(n!=="__source"&&!(n in e))return!0;for(var r in e)if(r!=="__source"&&t[r]!==e[r])return!0;return!1}function Kt(t){this.props=t}(Kt.prototype=new te).isPureReactComponent=!0,Kt.prototype.shouldComponentUpdate=function(t,e){return Vt(this.props,t)||Vt(this.state,e)};var gn=j.__b;j.__b=function(t){t.type&&t.type.__f&&t.ref&&(t.props.ref=t.ref,t.ref=null),gn&&gn(t)};var to=typeof Symbol<"u"&&Symbol.for&&Symbol.for("react.forward_ref")||3911,_n=function(t,e){return t==null?null:ie(ie(t).map(e))},no={map:_n,forEach:_n,count:function(t){return t?ie(t).length:0},only:function(t){var e=ie(t);if(e.length!==1)throw"Children.only";return e[0]},toArray:ie},ro=j.__e;function St(){this.__u=0,this.t=null,this.__b=null}function wr(t){var e=t.__.__c;return e&&e.__e&&e.__e(t)}function Le(){this.u=null,this.o=null}j.__e=function(t,e,n){if(t.then){for(var r,o=e;o=o.__;)if((r=o.__c)&&r.__c)return e.__e==null&&(e.__e=n.__e,e.__k=n.__k),r.__c(t,e)}ro(t,e,n)},(St.prototype=new te).__c=function(t,e){var n=e.__c,r=this;r.t==null&&(r.t=[]),r.t.push(n);var o=wr(r.__v),i=!1,u=function(){i||(i=!0,n.componentWillUnmount=n.__c,o?o(s):s())};n.__c=n.componentWillUnmount,n.componentWillUnmount=function(){u(),n.__c&&n.__c()};var s=function(){if(!--r.__u){if(r.state.__e){var f=r.state.__e;r.__v.__k[0]=function h(y,d,v){return y&&(y.__v=null,y.__k=y.__k&&y.__k.map(function(p){return h(p,d,v)}),y.__c&&y.__c.__P===d&&(y.__e&&v.insertBefore(y.__e,y.__d),y.__c.__e=!0,y.__c.__P=v)),y}(f,f.__c.__P,f.__c.__O)}var a;for(r.setState({__e:r.__b=null});a=r.t.pop();)a.forceUpdate()}},l=e.__h===!0;r.__u++||l||r.setState({__e:r.__b=r.__v.__k[0]}),t.then(u,u)},St.prototype.componentWillUnmount=function(){this.t=[]},St.prototype.render=function(t,e){if(this.__b){if(this.__v.__k){var n=document.createElement("div"),r=this.__v.__k[0].__c;this.__v.__k[0]=function i(u,s,l){return u&&(u.__c&&u.__c.__H&&(u.__c.__H.__.forEach(function(f){typeof f.__c=="function"&&f.__c()}),u.__c.__H=null),(u=Or({},u)).__c!=null&&(u.__c.__P===l&&(u.__c.__P=s),u.__c=null),u.__k=u.__k&&u.__k.map(function(f){return i(f,s,l)})),u}(this.__b,n,r.__O=r.__P)}this.__b=null}var o=e.__e&&ee(pe,null,t.fallback);return o&&(o.__h=null),[ee(pe,null,e.__e?null:t.children),o]};var bn=function(t,e,n){if(++n[1]===n[0]&&t.o.delete(e),t.props.revealOrder&&(t.props.revealOrder[0]!=="t"||!t.o.size))for(n=t.u;n;){for(;n.length>3;)n.pop()();if(n[1]>>1,1),e.i.removeChild(r)}}),rt(ee(oo,{context:e.context},t.__v),e.l)):e.l&&e.componentWillUnmount()}function Er(t,e){return ee(io,{__v:t,i:e})}(Le.prototype=new te).__e=function(t){var e=this,n=wr(e.__v),r=e.o.get(t);return r[0]++,function(o){var i=function(){e.props.revealOrder?(r.push(o),bn(e,t,r)):o()};n?n(i):i()}},Le.prototype.render=function(t){this.u=null,this.o=new Map;var e=ie(t.children);t.revealOrder&&t.revealOrder[0]==="b"&&e.reverse();for(var n=e.length;n--;)this.o.set(e[n],this.u=[1,0,this.u]);return t.children},Le.prototype.componentDidUpdate=Le.prototype.componentDidMount=function(){var t=this;this.o.forEach(function(e,n){bn(t,n,e)})};var jr=typeof Symbol<"u"&&Symbol.for&&Symbol.for("react.element")||60103,ao=/^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|fill|flood|font|glyph(?!R)|horiz|marker(?!H|W|U)|overline|paint|stop|strikethrough|stroke|text(?!L)|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/,co=function(t){return(typeof Symbol<"u"&&D(Symbol())=="symbol"?/fil|che|rad/i:/fil|che|ra/i).test(t)};function Pr(t,e,n){return e.__k==null&&(e.textContent=""),rt(t,e),typeof n=="function"&&n(),t?t.__c:null}te.prototype.isReactComponent={},["componentWillMount","componentWillReceiveProps","componentWillUpdate"].forEach(function(t){Object.defineProperty(te.prototype,t,{configurable:!0,get:function(){return this["UNSAFE_"+t]},set:function(e){Object.defineProperty(this,t,{configurable:!0,writable:!0,value:e})}})});var Sn=j.event;function uo(){}function lo(){return this.cancelBubble}function so(){return this.defaultPrevented}j.event=function(t){return Sn&&(t=Sn(t)),t.persist=uo,t.isPropagationStopped=lo,t.isDefaultPrevented=so,t.nativeEvent=t};var Ir,On={configurable:!0,get:function(){return this.class}},wn=j.vnode;j.vnode=function(t){var e=t.type,n=t.props,r=n;if(typeof e=="string"){for(var o in r={},n){var i=n[o];o==="value"&&"defaultValue"in n&&i==null||(o==="defaultValue"&&"value"in n&&n.value==null?o="value":o==="download"&&i===!0?i="":/ondoubleclick/i.test(o)?o="ondblclick":/^onchange(textarea|input)/i.test(o+e)&&!co(n.type)?o="oninput":/^on(Ani|Tra|Tou|BeforeInp)/.test(o)?o=o.toLowerCase():ao.test(o)?o=o.replace(/[A-Z0-9]/,"-$&").toLowerCase():i===null&&(i=void 0),r[o]=i)}e=="select"&&r.multiple&&Array.isArray(r.value)&&(r.value=ie(n.children).forEach(function(u){u.props.selected=r.value.indexOf(u.props.value)!=-1})),e=="select"&&r.defaultValue!=null&&(r.value=ie(n.children).forEach(function(u){u.props.selected=r.multiple?r.defaultValue.indexOf(u.props.value)!=-1:r.defaultValue==u.props.value})),t.props=r}e&&n.class!=n.className&&(On.enumerable="className"in n,n.className!=null&&(r.class=n.className),Object.defineProperty(r,"className",On)),t.$$typeof=jr,wn&&wn(t)};var En=j.__r;j.__r=function(t){En&&En(t),Ir=t.__c};var fo={ReactCurrentDispatcher:{current:{readContext:function(t){return Ir.__n[t.__c].props.value}}}};function jn(t){return!!t&&t.$$typeof===jr}(typeof performance>"u"?"undefined":D(performance))=="object"&&typeof performance.now=="function"&&performance.now.bind(performance);var c={useState:Gt,useReducer:br,useEffect:Yt,useLayoutEffect:hn,useRef:function(t){return Ce=5,Ct(function(){return{current:t}},[])},useImperativeHandle:function(t,e,n){Ce=6,hn(function(){typeof t=="function"?t(e()):t&&(t.current=e())},n==null?n:n.concat(t))},useMemo:Ct,useCallback:function(t,e){return Ce=8,Ct(function(){return t},e)},useContext:function(t){var e=K.context[t.__c],n=it(xe++,9);return n.__c=t,e?(n.__==null&&(n.__=!0,e.sub(K)),e.props.value):t.__},useDebugValue:function(t,e){j.useDebugValue&&j.useDebugValue(e?e(t):t)},version:"16.8.0",Children:no,render:Pr,hydrate:function(t,e,n){return _r(t,e),typeof n=="function"&&n(),t?t.__c:null},unmountComponentAtNode:function(t){return!!t.__k&&(rt(null,t),!0)},createPortal:Er,createElement:ee,createContext:function(t,e){var n={__c:e="__cC"+sr++,__:t,Consumer:function(r,o){return r.children(o)},Provider:function(r){var o,i;return this.getChildContext||(o=[],(i={})[e]=this,this.getChildContext=function(){return i},this.shouldComponentUpdate=function(u){this.props.value!==u.value&&o.some(Ut)},this.sub=function(u){o.push(u);var s=u.componentWillUnmount;u.componentWillUnmount=function(){o.splice(o.indexOf(u),1),s&&s.call(u)}}),r.children}};return n.Provider.__=n.Consumer.contextType=n},createFactory:function(t){return ee.bind(null,t)},cloneElement:function(t){return jn(t)?Xr.apply(null,arguments):t},createRef:function(){return{current:null}},Fragment:pe,isValidElement:jn,findDOMNode:function(t){return t&&(t.base||t.nodeType===1&&t)||null},Component:te,PureComponent:Kt,memo:function(t,e){function n(o){var i=this.props.ref,u=i==o.ref;return!u&&i&&(i.call?i(null):i.current=null),e?!e(this.props,o)||!u:Vt(this.props,o)}function r(o){return this.shouldComponentUpdate=n,ee(t,o)}return r.displayName="Memo("+(t.displayName||t.name)+")",r.prototype.isReactComponent=!0,r.__f=!0,r},forwardRef:function(t){function e(n,r){var o=Or({},n);return delete o.ref,t(o,(r=n.ref||r)&&(D(r)!="object"||"current"in r)?r:null)}return e.$$typeof=to,e.render=e,e.prototype.isReactComponent=e.__f=!0,e.displayName="ForwardRef("+(t.displayName||t.name)+")",e},unstable_batchedUpdates:function(t,e){return t(e)},StrictMode:pe,Suspense:St,SuspenseList:Le,lazy:function(t){var e,n,r;function o(i){if(e||(e=t()).then(function(u){n=u.default||u},function(u){r=u}),r)throw r;if(!n)throw e;return ee(n,i)}return o.displayName="Lazy",o.__f=!0,o},__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED:fo},mo=["facetName","facetQuery"];function Pn(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter(function(o){return Object.getOwnPropertyDescriptor(t,o).enumerable})),n.push.apply(n,r)}return n}function Fe(t){for(var e=1;e=0||(a[l]=u[l]);return a}(t,e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(o[n]=t[n])}return o}function be(t,e){return function(n){if(Array.isArray(n))return n}(t)||function(n,r){var o=n==null?null:typeof Symbol<"u"&&n[Symbol.iterator]||n["@@iterator"];if(o!=null){var i,u,s=[],l=!0,f=!1;try{for(o=o.call(n);!(l=(i=o.next()).done)&&(s.push(i.value),!r||s.length!==r);l=!0);}catch(a){f=!0,u=a}finally{try{l||o.return==null||o.return()}finally{if(f)throw u}}return s}}(t,e)||Dr(t,e)||function(){throw new TypeError(`Invalid attempt to destructure non-iterable instance. +In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}()}function Dr(t,e){if(t){if(typeof t=="string")return Wt(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return n==="Object"&&t.constructor&&(n=t.constructor.name),n==="Map"||n==="Set"?Array.from(t):n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?Wt(t,e):void 0}}function Wt(t,e){(e==null||e>t.length)&&(e=t.length);for(var n=0,r=new Array(e);nt.length)&&(e=t.length);for(var n=0,r=new Array(e);nt.length)&&(e=t.length);for(var n=0,r=new Array(e);n=0||(a[l]=u[l]);return a}(t,e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(o[n]=t[n])}return o}function An(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter(function(o){return Object.getOwnPropertyDescriptor(t,o).enumerable})),n.push.apply(n,r)}return n}function Ae(t){for(var e=1;e1&&arguments[1]!==void 0?arguments[1]:20,n=[],r=0;rt.length)&&(e=t.length);for(var n=0,r=new Array(e);n=3||y===2&&d>=4||y===1&&d>=10);function p(m,g,_){if(v&&_!==void 0){var b=_[0].__autocomplete_algoliaCredentials,S={"X-Algolia-Application-Id":b.appId,"X-Algolia-API-Key":b.apiKey};a.apply(void 0,[m].concat(st(g),[{headers:S}]))}else a.apply(void 0,[m].concat(st(g)))}return{init:function(m,g){a("init",{appId:m,apiKey:g})},setUserToken:function(m){a("setUserToken",m)},clickedObjectIDsAfterSearch:function(){for(var m=arguments.length,g=new Array(m),_=0;_0&&p("clickedObjectIDsAfterSearch",ft(g),g[0].items)},clickedObjectIDs:function(){for(var m=arguments.length,g=new Array(m),_=0;_0&&p("clickedObjectIDs",ft(g),g[0].items)},clickedFilters:function(){for(var m=arguments.length,g=new Array(m),_=0;_0&&a.apply(void 0,["clickedFilters"].concat(g))},convertedObjectIDsAfterSearch:function(){for(var m=arguments.length,g=new Array(m),_=0;_0&&p("convertedObjectIDsAfterSearch",ft(g),g[0].items)},convertedObjectIDs:function(){for(var m=arguments.length,g=new Array(m),_=0;_0&&p("convertedObjectIDs",ft(g),g[0].items)},convertedFilters:function(){for(var m=arguments.length,g=new Array(m),_=0;_0&&a.apply(void 0,["convertedFilters"].concat(g))},viewedObjectIDs:function(){for(var m=arguments.length,g=new Array(m),_=0;_0&&g.reduce(function(b,S){var O=S.items,E=xr(S,So);return[].concat(st(b),st(wo(Ae(Ae({},E),{},{objectIDs:(O==null?void 0:O.map(function(k){return k.objectID}))||E.objectIDs})).map(function(k){return{items:O,payload:k}})))},[]).forEach(function(b){var S=b.items;return p("viewedObjectIDs",[b.payload],S)})},viewedFilters:function(){for(var m=arguments.length,g=new Array(m),_=0;_0&&a.apply(void 0,["viewedFilters"].concat(g))}}}(u),l={current:[]},f=Cr(function(a){var h=a.state;if(h.isOpen){var y=h.collections.reduce(function(d,v){return[].concat(Oe(d),Oe(v.items))},[]).filter(xt);Ar(l.current.map(function(d){return d.objectID}),y.map(function(d){return d.objectID}))||(l.current=y,y.length>0&&Io({onItemsChange:r,items:y,insights:s,state:h}))}},0);return{name:"aa.algoliaInsightsPlugin",subscribe:function(a){var h=a.setContext,y=a.onSelect,d=a.onActive;u("addAlgoliaAgent","insights-plugin"),h({algoliaInsightsPlugin:{__algoliaSearchParameters:{clickAnalytics:!0},insights:s}}),y(function(v){var p=v.item,m=v.state,g=v.event;xt(p)&&o({state:m,event:g,insights:s,item:p,insightsEvents:[me({eventName:"Item Selected"},kn({item:p,items:l.current}))]})}),d(function(v){var p=v.item,m=v.state,g=v.event;xt(p)&&i({state:m,event:g,insights:s,item:p,insightsEvents:[me({eventName:"Item Active"},kn({item:p,items:l.current}))]})})},onStateChange:function(a){var h=a.state;f({state:h})},__autocomplete_pluginOptions:t}}function wt(t,e){var n=e;return{then:function(r,o){return wt(t.then(mt(r,n,t),mt(o,n,t)),n)},catch:function(r){return wt(t.catch(mt(r,n,t)),n)},finally:function(r){return r&&n.onCancelList.push(r),wt(t.finally(mt(r&&function(){return n.onCancelList=[],r()},n,t)),n)},cancel:function(){n.isCanceled=!0;var r=n.onCancelList;n.onCancelList=[],r.forEach(function(o){o()})},isCanceled:function(){return n.isCanceled===!0}}}function Nn(t){return wt(t,{isCanceled:!1,onCancelList:[]})}function mt(t,e,n){return t?function(r){return e.isCanceled?r:t(r)}:n}function Tn(t,e,n,r){if(!n)return null;if(t<0&&(e===null||r!==null&&e===0))return n+t;var o=(e===null?-1:e)+t;return o<=-1||o>=n?r===null?null:0:o}function Rn(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter(function(o){return Object.getOwnPropertyDescriptor(t,o).enumerable})),n.push.apply(n,r)}return n}function qn(t){for(var e=1;et.length)&&(e=t.length);for(var n=0,r=new Array(e);nt.length)&&(e=t.length);for(var n=0,r=new Array(e);n=0||(M[w]=P[w]);return M}(_,b);if(Object.getOwnPropertySymbols){var k=Object.getOwnPropertySymbols(_);for(O=0;O=0||Object.prototype.propertyIsEnumerable.call(_,S)&&(E[S]=_[S])}return E}(t,qo);qe&&o.environment.clearTimeout(qe);var f=l.setCollections,a=l.setIsOpen,h=l.setQuery,y=l.setActiveItemId,d=l.setStatus;if(h(i),y(o.defaultActiveItemId),!i&&o.openOnFocus===!1){var v,p=s.getState().collections.map(function(_){return Re(Re({},_),{},{items:[]})});d("idle"),f(p),a((v=r.isOpen)!==null&&v!==void 0?v:o.shouldPanelOpen({state:s.getState()}));var m=Nn(Kn(p).then(function(){return Promise.resolve()}));return s.pendingRequests.add(m)}d("loading"),qe=o.environment.setTimeout(function(){d("stalled")},o.stallThreshold);var g=Nn(Kn(o.getSources(Re({query:i,refresh:u,state:s.getState()},l)).then(function(_){return Promise.all(_.map(function(b){return Promise.resolve(b.getItems(Re({query:i,refresh:u,state:s.getState()},l))).then(function(S){return function(O,E,k){if(I=O,!!(I!=null&&I.execute)){var P=O.requesterId==="algolia"?Object.assign.apply(Object,[{}].concat(Tr(Object.keys(k.context).map(function(w){var T;return(T=k.context[w])===null||T===void 0?void 0:T.__algoliaSearchParameters})))):{};return Ee(Ee({},O),{},{requests:O.queries.map(function(w){return{query:O.requesterId==="algolia"?Ee(Ee({},w),{},{params:Ee(Ee({},P),w.params)}):w,sourceId:E,transformResponse:O.transformResponse}})})}var I;return{items:O,sourceId:E}}(S,b.sourceId,s.getState())})})).then(Ro).then(function(b){return function(S,O,E){return O.map(function(k){var P,I=S.filter(function(C){return C.sourceId===k.sourceId}),w=I.map(function(C){return C.items}),T=I[0].transformResponse,M=T?T({results:P=w,hits:P.map(function(C){return C.hits}).filter(Boolean),facetHits:P.map(function(C){var z;return(z=C.facetHits)===null||z===void 0?void 0:z.map(function(ae){return{label:ae.value,count:ae.count,_highlightResult:{label:{value:ae.highlighted}}}})}).filter(Boolean)}):w;return k.onResolve({source:k,results:w,items:M,state:E.getState()}),M.every(Boolean),'The `getItems` function from source "'.concat(k.sourceId,'" must return an array of items but returned ').concat(JSON.stringify(void 0),`. + +Did you forget to return items? + +See: https://www.algolia.com/doc/ui-libraries/autocomplete/core-concepts/sources/#param-getitems`),{source:k,items:M}})}(b,_,s)}).then(function(b){return function(S){var O=S.props,E=S.state,k=S.collections.reduce(function(I,w){return vt(vt({},I),{},Nr({},w.source.sourceId,vt(vt({},w.source),{},{getItems:function(){return ot(w.items)}})))},{}),P=O.plugins.reduce(function(I,w){return w.reshape?w.reshape(I):I},{sourcesBySourceId:k,state:E}).sourcesBySourceId;return ot(O.reshape({sourcesBySourceId:P,sources:Object.values(P),state:E})).filter(Boolean).map(function(I){return{source:I,items:I.getItems()}})}({collections:b,props:o,state:s.getState()})})}))).then(function(_){var b;d("idle"),f(_);var S=o.shouldPanelOpen({state:s.getState()});a((b=r.isOpen)!==null&&b!==void 0?b:o.openOnFocus&&!i&&S||S);var O=De(s.getState());if(s.getState().activeItemId!==null&&O){var E=O.item,k=O.itemInputValue,P=O.itemUrl,I=O.source;I.onActive(Re({event:e,item:E,itemInputValue:k,itemUrl:P,refresh:u,source:I,state:s.getState()},l))}}).finally(function(){d("idle"),qe&&o.environment.clearTimeout(qe)});return s.pendingRequests.add(g)}function Ge(t){return Ge=typeof Symbol=="function"&&D(Symbol.iterator)=="symbol"?function(e){return D(e)}:function(e){return e&&typeof Symbol=="function"&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":D(e)},Ge(t)}var Mo=["event","props","refresh","store"];function Wn(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter(function(o){return Object.getOwnPropertyDescriptor(t,o).enumerable})),n.push.apply(n,r)}return n}function ye(t){for(var e=1;e=0||(a[l]=u[l]);return a}(t,e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(o[n]=t[n])}return o}function Xe(t){return Xe=typeof Symbol=="function"&&D(Symbol.iterator)=="symbol"?function(e){return D(e)}:function(e){return e&&typeof Symbol=="function"&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":D(e)},Xe(t)}function Jn(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter(function(o){return Object.getOwnPropertyDescriptor(t,o).enumerable})),n.push.apply(n,r)}return n}function $o(t){for(var e=1;e0},reshape:function(d){return d.sources}},l),{},{id:(a=l.id)!==null&&a!==void 0?a:"autocomplete-".concat(go++),plugins:y,initialState:we({activeItemId:null,query:"",completion:null,collections:[],isOpen:!1,status:"idle",context:{}},l.initialState),onStateChange:function(d){var v;(v=l.onStateChange)===null||v===void 0||v.call(l,d),y.forEach(function(p){var m;return(m=p.onStateChange)===null||m===void 0?void 0:m.call(p,d)})},onSubmit:function(d){var v;(v=l.onSubmit)===null||v===void 0||v.call(l,d),y.forEach(function(p){var m;return(m=p.onSubmit)===null||m===void 0?void 0:m.call(p,d)})},onReset:function(d){var v;(v=l.onReset)===null||v===void 0||v.call(l,d),y.forEach(function(p){var m;return(m=p.onReset)===null||m===void 0?void 0:m.call(p,d)})},getSources:function(d){return Promise.all([].concat(function(v){return function(p){if(Array.isArray(p))return Tt(p)}(v)||function(p){if(typeof Symbol<"u"&&p[Symbol.iterator]!=null||p["@@iterator"]!=null)return Array.from(p)}(v)||function(p,m){if(p){if(typeof p=="string")return Tt(p,m);var g=Object.prototype.toString.call(p).slice(8,-1);return g==="Object"&&p.constructor&&(g=p.constructor.name),g==="Map"||g==="Set"?Array.from(p):g==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(g)?Tt(p,m):void 0}}(v)||function(){throw new TypeError(`Invalid attempt to spread non-iterable instance. +In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}()}(y.map(function(v){return v.getSources})),[l.getSources]).filter(Boolean).map(function(v){return function(p,m){var g=[];return Promise.resolve(p(m)).then(function(_){return Promise.all(_.filter(function(b){return!!b}).map(function(b){if(b.sourceId,g.includes(b.sourceId))throw new Error("[Autocomplete] The `sourceId` ".concat(JSON.stringify(b.sourceId)," is not unique."));g.push(b.sourceId);var S={getItemInputValue:function(E){return E.state.query},getItemUrl:function(){},onSelect:function(E){(0,E.setIsOpen)(!1)},onActive:Ot,onResolve:Ot};Object.keys(S).forEach(function(E){S[E].__default=!0});var O=qn(qn({},S),b);return Promise.resolve(O)}))})}(v,d)})).then(function(v){return ot(v)}).then(function(v){return v.map(function(p){return we(we({},p),{},{onSelect:function(m){p.onSelect(m),f.forEach(function(g){var _;return(_=g.onSelect)===null||_===void 0?void 0:_.call(g,m)})},onActive:function(m){p.onActive(m),f.forEach(function(g){var _;return(_=g.onActive)===null||_===void 0?void 0:_.call(g,m)})},onResolve:function(m){p.onResolve(m),f.forEach(function(g){var _;return(_=g.onResolve)===null||_===void 0?void 0:_.call(g,m)})}})})})},navigator:we({navigate:function(d){var v=d.itemUrl;h.location.assign(v)},navigateNewTab:function(d){var v=d.itemUrl,p=h.open(v,"_blank","noopener");p==null||p.focus()},navigateNewWindow:function(d){var v=d.itemUrl;h.open(v,"_blank","noopener")}},l.navigator)})}(t,e),r=function(l,f,a){var h,y=f.initialState;return{getState:function(){return y},dispatch:function(d,v){var p=function(m){for(var g=1;g=0||(ct[G]=Se[G]);return ct}(L,ne);if(Object.getOwnPropertySymbols){var Q=Object.getOwnPropertySymbols(L);for(V=0;V=0||Object.prototype.propertyIsEnumerable.call(L,$)&&(ce[$]=L[$])}return ce}(I,Mo);if(w.key==="ArrowUp"||w.key==="ArrowDown"){var ae=function(){var L=T.environment.document.getElementById("".concat(T.id,"-item-").concat(C.getState().activeItemId));L&&(L.scrollIntoViewIfNeeded?L.scrollIntoViewIfNeeded(!1):L.scrollIntoView(!1))},at=function(){var L=De(C.getState());if(C.getState().activeItemId!==null&&L){var ne=L.item,$=L.itemInputValue,V=L.itemUrl,ce=L.source;ce.onActive(ye({event:w,item:ne,itemInputValue:$,itemUrl:V,refresh:M,source:ce,state:C.getState()},z))}};w.preventDefault(),C.getState().isOpen===!1&&(T.openOnFocus||C.getState().query)?je(ye({event:w,props:T,query:C.getState().query,refresh:M,store:C},z)).then(function(){C.dispatch(w.key,{nextActiveItemId:T.defaultActiveItemId}),at(),setTimeout(ae,0)}):(C.dispatch(w.key,{}),at(),ae())}else if(w.key==="Escape")w.preventDefault(),C.dispatch(w.key,null),C.pendingRequests.cancelAll();else if(w.key==="Tab")C.dispatch("blur",null),C.pendingRequests.cancelAll();else if(w.key==="Enter"){if(C.getState().activeItemId===null||C.getState().collections.every(function(L){return L.items.length===0}))return void(T.debug||C.pendingRequests.cancelAll());w.preventDefault();var de=De(C.getState()),H=de.item,he=de.itemInputValue,J=de.itemUrl,Z=de.source;if(w.metaKey||w.ctrlKey)J!==void 0&&(Z.onSelect(ye({event:w,item:H,itemInputValue:he,itemUrl:J,refresh:M,source:Z,state:C.getState()},z)),T.navigator.navigateNewTab({itemUrl:J,item:H,state:C.getState()}));else if(w.shiftKey)J!==void 0&&(Z.onSelect(ye({event:w,item:H,itemInputValue:he,itemUrl:J,refresh:M,source:Z,state:C.getState()},z)),T.navigator.navigateNewWindow({itemUrl:J,item:H,state:C.getState()}));else if(!w.altKey){if(J!==void 0)return Z.onSelect(ye({event:w,item:H,itemInputValue:he,itemUrl:J,refresh:M,source:Z,state:C.getState()},z)),void T.navigator.navigate({itemUrl:J,item:H,state:C.getState()});je(ye({event:w,nextState:{isOpen:!1},props:T,query:he,refresh:M,store:C},z)).then(function(){Z.onSelect(ye({event:w,item:H,itemInputValue:he,itemUrl:J,refresh:M,source:Z,state:C.getState()},z))})}}})(F({event:P,props:f,refresh:a,store:h},y))},onFocus:m,onBlur:Ot,onClick:function(P){v.inputElement!==f.environment.document.activeElement||h.getState().isOpen||m(P)}},S)},getPanelProps:function(v){return F({onMouseDown:function(p){p.preventDefault()},onMouseLeave:function(){h.dispatch("mouseleave",null)}},v)},getListProps:function(v){var p=v||{},m=p.sourceIndex,g=ge(p,Wo);return F({role:"listbox","aria-labelledby":"".concat(d(f.id,m),"-label"),id:"".concat(d(f.id,m),"-list")},g)},getItemProps:function(v){var p=v.item,m=v.source,g=v.sourceIndex,_=ge(v,zo);return F({id:"".concat(d(f.id,g),"-item-").concat(p.__autocomplete_id),role:"option","aria-selected":h.getState().activeItemId===p.__autocomplete_id,onMouseMove:function(b){if(p.__autocomplete_id!==h.getState().activeItemId){h.dispatch("mousemove",p.__autocomplete_id);var S=De(h.getState());if(h.getState().activeItemId!==null&&S){var O=S.item,E=S.itemInputValue,k=S.itemUrl,P=S.source;P.onActive(F({event:b,item:O,itemInputValue:E,itemUrl:k,refresh:a,source:P,state:h.getState()},y))}}},onMouseDown:function(b){b.preventDefault()},onClick:function(b){var S=m.getItemInputValue({item:p,state:h.getState()}),O=m.getItemUrl({item:p,state:h.getState()});(O?Promise.resolve():je(F({event:b,nextState:{isOpen:!1},props:f,query:S,refresh:a,store:h},y))).then(function(){m.onSelect(F({event:b,item:p,itemInputValue:S,itemUrl:O,refresh:a,source:m,state:h.getState()},y))})}},_)}}}(_e({props:n,refresh:u,store:r,navigator:n.navigator},o));function u(){return je(_e({event:new Event("input"),nextState:{isOpen:r.getState().isOpen},props:n,navigator:n.navigator,query:r.getState().query,refresh:u,store:r},o))}if(t.insights&&!n.plugins.some(function(l){return l.name==="aa.algoliaInsightsPlugin"})){var s=typeof t.insights=="boolean"?{}:t.insights;n.plugins.push(Do(s))}return n.plugins.forEach(function(l){var f;return(f=l.subscribe)===null||f===void 0?void 0:f.call(l,_e(_e({},o),{},{navigator:n.navigator,refresh:u,onSelect:function(a){e.push({onSelect:a})},onActive:function(a){e.push({onActive:a})},onResolve:function(a){e.push({onResolve:a})}}))}),function(l){var f,a,h=l.metadata,y=l.environment;if(!((f=y.navigator)===null||f===void 0||(a=f.userAgent)===null||a===void 0)&&a.includes("Algolia Crawler")){var d=y.document.createElement("meta"),v=y.document.querySelector("head");d.name="algolia:metadata",setTimeout(function(){d.content=JSON.stringify(h),v.appendChild(d)},0)}}({metadata:Zo({plugins:n.plugins,options:t}),environment:n.environment}),_e(_e({refresh:u,navigator:n.navigator},i),o)}function ei(t){var e=t.translations,n=(e===void 0?{}:e).searchByText,r=n===void 0?"Search by":n;return c.createElement("a",{href:"https://www.algolia.com/ref/docsearch/?utm_source=".concat(window.location.hostname,"&utm_medium=referral&utm_content=powered_by&utm_campaign=docsearch"),target:"_blank",rel:"noopener noreferrer"},c.createElement("span",{className:"DocSearch-Label"},r),c.createElement("svg",{width:"77",height:"19","aria-label":"Algolia",role:"img",id:"Layer_1",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 2196.2 500"},c.createElement("defs",null,c.createElement("style",null,".cls-1,.cls-2{fill:#003dff;}.cls-2{fill-rule:evenodd;}")),c.createElement("path",{className:"cls-2",d:"M1070.38,275.3V5.91c0-3.63-3.24-6.39-6.82-5.83l-50.46,7.94c-2.87,.45-4.99,2.93-4.99,5.84l.17,273.22c0,12.92,0,92.7,95.97,95.49,3.33,.1,6.09-2.58,6.09-5.91v-40.78c0-2.96-2.19-5.51-5.12-5.84-34.85-4.01-34.85-47.57-34.85-54.72Z"}),c.createElement("rect",{className:"cls-1",x:"1845.88",y:"104.73",width:"62.58",height:"277.9",rx:"5.9",ry:"5.9"}),c.createElement("path",{className:"cls-2",d:"M1851.78,71.38h50.77c3.26,0,5.9-2.64,5.9-5.9V5.9c0-3.62-3.24-6.39-6.82-5.83l-50.77,7.95c-2.87,.45-4.99,2.92-4.99,5.83v51.62c0,3.26,2.64,5.9,5.9,5.9Z"}),c.createElement("path",{className:"cls-2",d:"M1764.03,275.3V5.91c0-3.63-3.24-6.39-6.82-5.83l-50.46,7.94c-2.87,.45-4.99,2.93-4.99,5.84l.17,273.22c0,12.92,0,92.7,95.97,95.49,3.33,.1,6.09-2.58,6.09-5.91v-40.78c0-2.96-2.19-5.51-5.12-5.84-34.85-4.01-34.85-47.57-34.85-54.72Z"}),c.createElement("path",{className:"cls-2",d:"M1631.95,142.72c-11.14-12.25-24.83-21.65-40.78-28.31-15.92-6.53-33.26-9.85-52.07-9.85-18.78,0-36.15,3.17-51.92,9.85-15.59,6.66-29.29,16.05-40.76,28.31-11.47,12.23-20.38,26.87-26.76,44.03-6.38,17.17-9.24,37.37-9.24,58.36,0,20.99,3.19,36.87,9.55,54.21,6.38,17.32,15.14,32.11,26.45,44.36,11.29,12.23,24.83,21.62,40.6,28.46,15.77,6.83,40.12,10.33,52.4,10.48,12.25,0,36.78-3.82,52.7-10.48,15.92-6.68,29.46-16.23,40.78-28.46,11.29-12.25,20.05-27.04,26.25-44.36,6.22-17.34,9.24-33.22,9.24-54.21,0-20.99-3.34-41.19-10.03-58.36-6.38-17.17-15.14-31.8-26.43-44.03Zm-44.43,163.75c-11.47,15.75-27.56,23.7-48.09,23.7-20.55,0-36.63-7.8-48.1-23.7-11.47-15.75-17.21-34.01-17.21-61.2,0-26.89,5.59-49.14,17.06-64.87,11.45-15.75,27.54-23.52,48.07-23.52,20.55,0,36.63,7.78,48.09,23.52,11.47,15.57,17.36,37.98,17.36,64.87,0,27.19-5.72,45.3-17.19,61.2Z"}),c.createElement("path",{className:"cls-2",d:"M894.42,104.73h-49.33c-48.36,0-90.91,25.48-115.75,64.1-14.52,22.58-22.99,49.63-22.99,78.73,0,44.89,20.13,84.92,51.59,111.1,2.93,2.6,6.05,4.98,9.31,7.14,12.86,8.49,28.11,13.47,44.52,13.47,1.23,0,2.46-.03,3.68-.09,.36-.02,.71-.05,1.07-.07,.87-.05,1.75-.11,2.62-.2,.34-.03,.68-.08,1.02-.12,.91-.1,1.82-.21,2.73-.34,.21-.03,.42-.07,.63-.1,32.89-5.07,61.56-30.82,70.9-62.81v57.83c0,3.26,2.64,5.9,5.9,5.9h50.42c3.26,0,5.9-2.64,5.9-5.9V110.63c0-3.26-2.64-5.9-5.9-5.9h-56.32Zm0,206.92c-12.2,10.16-27.97,13.98-44.84,15.12-.16,.01-.33,.03-.49,.04-1.12,.07-2.24,.1-3.36,.1-42.24,0-77.12-35.89-77.12-79.37,0-10.25,1.96-20.01,5.42-28.98,11.22-29.12,38.77-49.74,71.06-49.74h49.33v142.83Z"}),c.createElement("path",{className:"cls-2",d:"M2133.97,104.73h-49.33c-48.36,0-90.91,25.48-115.75,64.1-14.52,22.58-22.99,49.63-22.99,78.73,0,44.89,20.13,84.92,51.59,111.1,2.93,2.6,6.05,4.98,9.31,7.14,12.86,8.49,28.11,13.47,44.52,13.47,1.23,0,2.46-.03,3.68-.09,.36-.02,.71-.05,1.07-.07,.87-.05,1.75-.11,2.62-.2,.34-.03,.68-.08,1.02-.12,.91-.1,1.82-.21,2.73-.34,.21-.03,.42-.07,.63-.1,32.89-5.07,61.56-30.82,70.9-62.81v57.83c0,3.26,2.64,5.9,5.9,5.9h50.42c3.26,0,5.9-2.64,5.9-5.9V110.63c0-3.26-2.64-5.9-5.9-5.9h-56.32Zm0,206.92c-12.2,10.16-27.97,13.98-44.84,15.12-.16,.01-.33,.03-.49,.04-1.12,.07-2.24,.1-3.36,.1-42.24,0-77.12-35.89-77.12-79.37,0-10.25,1.96-20.01,5.42-28.98,11.22-29.12,38.77-49.74,71.06-49.74h49.33v142.83Z"}),c.createElement("path",{className:"cls-2",d:"M1314.05,104.73h-49.33c-48.36,0-90.91,25.48-115.75,64.1-11.79,18.34-19.6,39.64-22.11,62.59-.58,5.3-.88,10.68-.88,16.14s.31,11.15,.93,16.59c4.28,38.09,23.14,71.61,50.66,94.52,2.93,2.6,6.05,4.98,9.31,7.14,12.86,8.49,28.11,13.47,44.52,13.47h0c17.99,0,34.61-5.93,48.16-15.97,16.29-11.58,28.88-28.54,34.48-47.75v50.26h-.11v11.08c0,21.84-5.71,38.27-17.34,49.36-11.61,11.08-31.04,16.63-58.25,16.63-11.12,0-28.79-.59-46.6-2.41-2.83-.29-5.46,1.5-6.27,4.22l-12.78,43.11c-1.02,3.46,1.27,7.02,4.83,7.53,21.52,3.08,42.52,4.68,54.65,4.68,48.91,0,85.16-10.75,108.89-32.21,21.48-19.41,33.15-48.89,35.2-88.52V110.63c0-3.26-2.64-5.9-5.9-5.9h-56.32Zm0,64.1s.65,139.13,0,143.36c-12.08,9.77-27.11,13.59-43.49,14.7-.16,.01-.33,.03-.49,.04-1.12,.07-2.24,.1-3.36,.1-1.32,0-2.63-.03-3.94-.1-40.41-2.11-74.52-37.26-74.52-79.38,0-10.25,1.96-20.01,5.42-28.98,11.22-29.12,38.77-49.74,71.06-49.74h49.33Z"}),c.createElement("path",{className:"cls-1",d:"M249.83,0C113.3,0,2,110.09,.03,246.16c-2,138.19,110.12,252.7,248.33,253.5,42.68,.25,83.79-10.19,120.3-30.03,3.56-1.93,4.11-6.83,1.08-9.51l-23.38-20.72c-4.75-4.21-11.51-5.4-17.36-2.92-25.48,10.84-53.17,16.38-81.71,16.03-111.68-1.37-201.91-94.29-200.13-205.96,1.76-110.26,92-199.41,202.67-199.41h202.69V407.41l-115-102.18c-3.72-3.31-9.42-2.66-12.42,1.31-18.46,24.44-48.53,39.64-81.93,37.34-46.33-3.2-83.87-40.5-87.34-86.81-4.15-55.24,39.63-101.52,94-101.52,49.18,0,89.68,37.85,93.91,85.95,.38,4.28,2.31,8.27,5.52,11.12l29.95,26.55c3.4,3.01,8.79,1.17,9.63-3.3,2.16-11.55,2.92-23.58,2.07-35.92-4.82-70.34-61.8-126.93-132.17-131.26-80.68-4.97-148.13,58.14-150.27,137.25-2.09,77.1,61.08,143.56,138.19,145.26,32.19,.71,62.03-9.41,86.14-26.95l150.26,133.2c6.44,5.71,16.61,1.14,16.61-7.47V9.48C499.66,4.25,495.42,0,490.18,0H249.83Z"})))}function yt(t){return c.createElement("svg",{width:"15",height:"15","aria-label":t.ariaLabel,role:"img"},c.createElement("g",{fill:"none",stroke:"currentColor",strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:"1.2"},t.children))}function ti(t){var e=t.translations,n=e===void 0?{}:e,r=n.selectText,o=r===void 0?"to select":r,i=n.selectKeyAriaLabel,u=i===void 0?"Enter key":i,s=n.navigateText,l=s===void 0?"to navigate":s,f=n.navigateUpKeyAriaLabel,a=f===void 0?"Arrow up":f,h=n.navigateDownKeyAriaLabel,y=h===void 0?"Arrow down":h,d=n.closeText,v=d===void 0?"to close":d,p=n.closeKeyAriaLabel,m=p===void 0?"Escape key":p,g=n.searchByText,_=g===void 0?"Search by":g;return c.createElement(c.Fragment,null,c.createElement("div",{className:"DocSearch-Logo"},c.createElement(ei,{translations:{searchByText:_}})),c.createElement("ul",{className:"DocSearch-Commands"},c.createElement("li",null,c.createElement("kbd",{className:"DocSearch-Commands-Key"},c.createElement(yt,{ariaLabel:u},c.createElement("path",{d:"M12 3.53088v3c0 1-1 2-2 2H4M7 11.53088l-3-3 3-3"}))),c.createElement("span",{className:"DocSearch-Label"},o)),c.createElement("li",null,c.createElement("kbd",{className:"DocSearch-Commands-Key"},c.createElement(yt,{ariaLabel:y},c.createElement("path",{d:"M7.5 3.5v8M10.5 8.5l-3 3-3-3"}))),c.createElement("kbd",{className:"DocSearch-Commands-Key"},c.createElement(yt,{ariaLabel:a},c.createElement("path",{d:"M7.5 11.5v-8M10.5 6.5l-3-3-3 3"}))),c.createElement("span",{className:"DocSearch-Label"},l)),c.createElement("li",null,c.createElement("kbd",{className:"DocSearch-Commands-Key"},c.createElement(yt,{ariaLabel:m},c.createElement("path",{d:"M13.6167 8.936c-.1065.3583-.6883.962-1.4875.962-.7993 0-1.653-.9165-1.653-2.1258v-.5678c0-1.2548.7896-2.1016 1.653-2.1016.8634 0 1.3601.4778 1.4875 1.0724M9 6c-.1352-.4735-.7506-.9219-1.46-.8972-.7092.0246-1.344.57-1.344 1.2166s.4198.8812 1.3445.9805C8.465 7.3992 8.968 7.9337 9 8.5c.032.5663-.454 1.398-1.4595 1.398C6.6593 9.898 6 9 5.963 8.4851m-1.4748.5368c-.2635.5941-.8099.876-1.5443.876s-1.7073-.6248-1.7073-2.204v-.4603c0-1.0416.721-2.131 1.7073-2.131.9864 0 1.6425 1.031 1.5443 2.2492h-2.956"}))),c.createElement("span",{className:"DocSearch-Label"},v))))}function ni(t){var e=t.hit,n=t.children;return c.createElement("a",{href:e.url},n)}function ri(){return c.createElement("svg",{viewBox:"0 0 38 38",stroke:"currentColor",strokeOpacity:".5"},c.createElement("g",{fill:"none",fillRule:"evenodd"},c.createElement("g",{transform:"translate(1 1)",strokeWidth:"2"},c.createElement("circle",{strokeOpacity:".3",cx:"18",cy:"18",r:"18"}),c.createElement("path",{d:"M36 18c0-9.94-8.06-18-18-18"},c.createElement("animateTransform",{attributeName:"transform",type:"rotate",from:"0 18 18",to:"360 18 18",dur:"1s",repeatCount:"indefinite"})))))}function oi(){return c.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},c.createElement("g",{stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"},c.createElement("path",{d:"M3.18 6.6a8.23 8.23 0 1112.93 9.94h0a8.23 8.23 0 01-11.63 0"}),c.createElement("path",{d:"M6.44 7.25H2.55V3.36M10.45 6v5.6M10.45 11.6L13 13"})))}function Jt(){return c.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},c.createElement("path",{d:"M10 10l5.09-5.09L10 10l5.09 5.09L10 10zm0 0L4.91 4.91 10 10l-5.09 5.09L10 10z",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"}))}function ii(){return c.createElement("svg",{className:"DocSearch-Hit-Select-Icon",width:"20",height:"20",viewBox:"0 0 20 20"},c.createElement("g",{stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"},c.createElement("path",{d:"M18 3v4c0 2-2 4-4 4H2"}),c.createElement("path",{d:"M8 17l-6-6 6-6"})))}var ai=function(){return c.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},c.createElement("path",{d:"M17 6v12c0 .52-.2 1-1 1H4c-.7 0-1-.33-1-1V2c0-.55.42-1 1-1h8l5 5zM14 8h-3.13c-.51 0-.87-.34-.87-.87V4",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinejoin:"round"}))};function ci(t){switch(t.type){case"lvl1":return c.createElement(ai,null);case"content":return c.createElement(li,null);default:return c.createElement(ui,null)}}function ui(){return c.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},c.createElement("path",{d:"M13 13h4-4V8H7v5h6v4-4H7V8H3h4V3v5h6V3v5h4-4v5zm-6 0v4-4H3h4z",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"}))}function li(){return c.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},c.createElement("path",{d:"M17 5H3h14zm0 5H3h14zm0 5H3h14z",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinejoin:"round"}))}function Gn(){return c.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},c.createElement("path",{d:"M10 14.2L5 17l1-5.6-4-4 5.5-.7 2.5-5 2.5 5 5.6.8-4 4 .9 5.5z",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinejoin:"round"}))}function si(){return c.createElement("svg",{width:"40",height:"40",viewBox:"0 0 20 20",fill:"none",fillRule:"evenodd",stroke:"currentColor",strokeLinecap:"round",strokeLinejoin:"round"},c.createElement("path",{d:"M19 4.8a16 16 0 00-2-1.2m-3.3-1.2A16 16 0 001.1 4.7M16.7 8a12 12 0 00-2.8-1.4M10 6a12 12 0 00-6.7 2M12.3 14.7a4 4 0 00-4.5 0M14.5 11.4A8 8 0 0010 10M3 16L18 2M10 18h0"}))}function fi(){return c.createElement("svg",{width:"40",height:"40",viewBox:"0 0 20 20",fill:"none",fillRule:"evenodd",stroke:"currentColor",strokeLinecap:"round",strokeLinejoin:"round"},c.createElement("path",{d:"M15.5 4.8c2 3 1.7 7-1 9.7h0l4.3 4.3-4.3-4.3a7.8 7.8 0 01-9.8 1m-2.2-2.2A7.8 7.8 0 0113.2 2.4M2 18L18 2"}))}function mi(t){var e=t.translations,n=e===void 0?{}:e,r=n.titleText,o=r===void 0?"Unable to fetch results":r,i=n.helpText,u=i===void 0?"You might want to check your network connection.":i;return c.createElement("div",{className:"DocSearch-ErrorScreen"},c.createElement("div",{className:"DocSearch-Screen-Icon"},c.createElement(si,null)),c.createElement("p",{className:"DocSearch-Title"},o),c.createElement("p",{className:"DocSearch-Help"},u))}var pi=["translations"];function vi(t){var e=t.translations,n=e===void 0?{}:e,r=ve(t,pi),o=n.noResultsText,i=o===void 0?"No results for":o,u=n.suggestedQueryText,s=u===void 0?"Try searching for":u,l=n.reportMissingResultsText,f=l===void 0?"Believe this query should return results?":l,a=n.reportMissingResultsLinkText,h=a===void 0?"Let us know.":a,y=r.state.context.searchSuggestions;return c.createElement("div",{className:"DocSearch-NoResults"},c.createElement("div",{className:"DocSearch-Screen-Icon"},c.createElement(fi,null)),c.createElement("p",{className:"DocSearch-Title"},i,' "',c.createElement("strong",null,r.state.query),'"'),y&&y.length>0&&c.createElement("div",{className:"DocSearch-NoResults-Prefill-List"},c.createElement("p",{className:"DocSearch-Help"},s,":"),c.createElement("ul",null,y.slice(0,3).reduce(function(d,v){return[].concat(function(p){return function(m){if(Array.isArray(m))return Wt(m)}(p)||function(m){if(typeof Symbol<"u"&&m[Symbol.iterator]!=null||m["@@iterator"]!=null)return Array.from(m)}(p)||Dr(p)||function(){throw new TypeError(`Invalid attempt to spread non-iterable instance. +In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}()}(d),[c.createElement("li",{key:v},c.createElement("button",{className:"DocSearch-Prefill",key:v,type:"button",onClick:function(){r.setQuery(v.toLowerCase()+" "),r.refresh(),r.inputRef.current.focus()}},v))])},[]))),r.getMissingResultsUrl&&c.createElement("p",{className:"DocSearch-Help"},"".concat(f," "),c.createElement("a",{href:r.getMissingResultsUrl({query:r.state.query}),target:"_blank",rel:"noopener noreferrer"},h)))}var di=["hit","attribute","tagName"];function Yn(t,e){return e.split(".").reduce(function(n,r){return n!=null&&n[r]?n[r]:null},t)}function Pe(t){var e=t.hit,n=t.attribute,r=t.tagName;return ee(r===void 0?"span":r,Fe(Fe({},ve(t,di)),{},{dangerouslySetInnerHTML:{__html:Yn(e,"_snippetResult.".concat(n,".value"))||Yn(e,n)}}))}function $t(t){return t.collection&&t.collection.items.length!==0?c.createElement("section",{className:"DocSearch-Hits"},c.createElement("div",{className:"DocSearch-Hit-source"},t.title),c.createElement("ul",t.getListProps(),t.collection.items.map(function(e,n){return c.createElement(hi,B({key:[t.title,e.objectID].join(":"),item:e,index:n},t))}))):null}function hi(t){var e=t.item,n=t.index,r=t.renderIcon,o=t.renderAction,i=t.getItemProps,u=t.onItemClick,s=t.collection,l=t.hitComponent,f=be(c.useState(!1),2),a=f[0],h=f[1],y=be(c.useState(!1),2),d=y[0],v=y[1],p=c.useRef(null),m=l;return c.createElement("li",B({className:["DocSearch-Hit",e.__docsearch_parent&&"DocSearch-Hit--Child",a&&"DocSearch-Hit--deleting",d&&"DocSearch-Hit--favoriting"].filter(Boolean).join(" "),onTransitionEnd:function(){p.current&&p.current()}},i({item:e,source:s.source,onClick:function(g){u(e,g)}})),c.createElement(m,{hit:e},c.createElement("div",{className:"DocSearch-Hit-Container"},r({item:e,index:n}),e.hierarchy[e.type]&&e.type==="lvl1"&&c.createElement("div",{className:"DocSearch-Hit-content-wrapper"},c.createElement(Pe,{className:"DocSearch-Hit-title",hit:e,attribute:"hierarchy.lvl1"}),e.content&&c.createElement(Pe,{className:"DocSearch-Hit-path",hit:e,attribute:"content"})),e.hierarchy[e.type]&&(e.type==="lvl2"||e.type==="lvl3"||e.type==="lvl4"||e.type==="lvl5"||e.type==="lvl6")&&c.createElement("div",{className:"DocSearch-Hit-content-wrapper"},c.createElement(Pe,{className:"DocSearch-Hit-title",hit:e,attribute:"hierarchy.".concat(e.type)}),c.createElement(Pe,{className:"DocSearch-Hit-path",hit:e,attribute:"hierarchy.lvl1"})),e.type==="content"&&c.createElement("div",{className:"DocSearch-Hit-content-wrapper"},c.createElement(Pe,{className:"DocSearch-Hit-title",hit:e,attribute:"content"}),c.createElement(Pe,{className:"DocSearch-Hit-path",hit:e,attribute:"hierarchy.lvl1"})),o({item:e,runDeleteTransition:function(g){h(!0),p.current=g},runFavoriteTransition:function(g){v(!0),p.current=g}}))))}function Xn(t,e,n){return t.reduce(function(r,o){var i=e(o);return r.hasOwnProperty(i)||(r[i]=[]),r[i].length<(n||5)&&r[i].push(o),r},{})}function er(t){return t}function gt(t){return t.button===1||t.altKey||t.ctrlKey||t.metaKey||t.shiftKey}function yi(){}var qr=/(|<\/mark>)/g,gi=RegExp(qr.source);function Lr(t){var e,n,r=t;if(!r.__docsearch_parent&&!t._highlightResult)return t.hierarchy.lvl0;var o=((r.__docsearch_parent?(e=r.__docsearch_parent)===null||e===void 0||(e=e._highlightResult)===null||e===void 0||(e=e.hierarchy)===null||e===void 0?void 0:e.lvl0:(n=t._highlightResult)===null||n===void 0||(n=n.hierarchy)===null||n===void 0?void 0:n.lvl0)||{}).value;return o&&gi.test(o)?o.replace(qr,""):o}function _i(t){return c.createElement("div",{className:"DocSearch-Dropdown-Container"},t.state.collections.map(function(e){if(e.items.length===0)return null;var n=Lr(e.items[0]);return c.createElement($t,B({},t,{key:e.source.sourceId,title:n,collection:e,renderIcon:function(r){var o,i=r.item,u=r.index;return c.createElement(c.Fragment,null,i.__docsearch_parent&&c.createElement("svg",{className:"DocSearch-Hit-Tree",viewBox:"0 0 24 54"},c.createElement("g",{stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"},i.__docsearch_parent!==((o=e.items[u+1])===null||o===void 0?void 0:o.__docsearch_parent)?c.createElement("path",{d:"M8 6v21M20 27H8.3"}):c.createElement("path",{d:"M8 6v42M20 27H8.3"}))),c.createElement("div",{className:"DocSearch-Hit-icon"},c.createElement(ci,{type:i.type})))},renderAction:function(){return c.createElement("div",{className:"DocSearch-Hit-action"},c.createElement(ii,null))}}))}),t.resultsFooterComponent&&c.createElement("section",{className:"DocSearch-HitsFooter"},c.createElement(t.resultsFooterComponent,{state:t.state})))}var bi=["translations"];function Si(t){var e=t.translations,n=e===void 0?{}:e,r=ve(t,bi),o=n.recentSearchesTitle,i=o===void 0?"Recent":o,u=n.noRecentSearchesText,s=u===void 0?"No recent searches":u,l=n.saveRecentSearchButtonTitle,f=l===void 0?"Save this search":l,a=n.removeRecentSearchButtonTitle,h=a===void 0?"Remove this search from history":a,y=n.favoriteSearchesTitle,d=y===void 0?"Favorite":y,v=n.removeFavoriteSearchButtonTitle,p=v===void 0?"Remove this search from favorites":v;return r.state.status==="idle"&&r.hasCollections===!1?r.disableUserPersonalization?null:c.createElement("div",{className:"DocSearch-StartScreen"},c.createElement("p",{className:"DocSearch-Help"},s)):r.hasCollections===!1?null:c.createElement("div",{className:"DocSearch-Dropdown-Container"},c.createElement($t,B({},r,{title:i,collection:r.state.collections[0],renderIcon:function(){return c.createElement("div",{className:"DocSearch-Hit-icon"},c.createElement(oi,null))},renderAction:function(m){var g=m.item,_=m.runFavoriteTransition,b=m.runDeleteTransition;return c.createElement(c.Fragment,null,c.createElement("div",{className:"DocSearch-Hit-action"},c.createElement("button",{className:"DocSearch-Hit-action-button",title:f,type:"submit",onClick:function(S){S.preventDefault(),S.stopPropagation(),_(function(){r.favoriteSearches.add(g),r.recentSearches.remove(g),r.refresh()})}},c.createElement(Gn,null))),c.createElement("div",{className:"DocSearch-Hit-action"},c.createElement("button",{className:"DocSearch-Hit-action-button",title:h,type:"submit",onClick:function(S){S.preventDefault(),S.stopPropagation(),b(function(){r.recentSearches.remove(g),r.refresh()})}},c.createElement(Jt,null))))}})),c.createElement($t,B({},r,{title:d,collection:r.state.collections[1],renderIcon:function(){return c.createElement("div",{className:"DocSearch-Hit-icon"},c.createElement(Gn,null))},renderAction:function(m){var g=m.item,_=m.runDeleteTransition;return c.createElement("div",{className:"DocSearch-Hit-action"},c.createElement("button",{className:"DocSearch-Hit-action-button",title:p,type:"submit",onClick:function(b){b.preventDefault(),b.stopPropagation(),_(function(){r.favoriteSearches.remove(g),r.refresh()})}},c.createElement(Jt,null)))}})))}var Oi=["translations"],wi=c.memo(function(t){var e=t.translations,n=e===void 0?{}:e,r=ve(t,Oi);if(r.state.status==="error")return c.createElement(mi,{translations:n==null?void 0:n.errorScreen});var o=r.state.collections.some(function(i){return i.items.length>0});return r.state.query?o===!1?c.createElement(vi,B({},r,{translations:n==null?void 0:n.noResultsScreen})):c.createElement(_i,r):c.createElement(Si,B({},r,{hasCollections:o,translations:n==null?void 0:n.startScreen}))},function(t,e){return e.state.status==="loading"||e.state.status==="stalled"}),Ei=["translations"];function ji(t){var e=t.translations,n=e===void 0?{}:e,r=ve(t,Ei),o=n.resetButtonTitle,i=o===void 0?"Clear the query":o,u=n.resetButtonAriaLabel,s=u===void 0?"Clear the query":u,l=n.cancelButtonText,f=l===void 0?"Cancel":l,a=n.cancelButtonAriaLabel,h=a===void 0?"Cancel":a,y=n.searchInputLabel,d=y===void 0?"Search":y,v=r.getFormProps({inputElement:r.inputRef.current}).onReset;return c.useEffect(function(){r.autoFocus&&r.inputRef.current&&r.inputRef.current.focus()},[r.autoFocus,r.inputRef]),c.useEffect(function(){r.isFromSelection&&r.inputRef.current&&r.inputRef.current.select()},[r.isFromSelection,r.inputRef]),c.createElement(c.Fragment,null,c.createElement("form",{className:"DocSearch-Form",onSubmit:function(p){p.preventDefault()},onReset:v},c.createElement("label",B({className:"DocSearch-MagnifierLabel"},r.getLabelProps()),c.createElement(kr,null),c.createElement("span",{className:"DocSearch-VisuallyHiddenForAccessibility"},d)),c.createElement("div",{className:"DocSearch-LoadingIndicator"},c.createElement(ri,null)),c.createElement("input",B({className:"DocSearch-Input",ref:r.inputRef},r.getInputProps({inputElement:r.inputRef.current,autoFocus:r.autoFocus,maxLength:64}))),c.createElement("button",{type:"reset",title:i,className:"DocSearch-Reset","aria-label":s,hidden:!r.state.query},c.createElement(Jt,null))),c.createElement("button",{className:"DocSearch-Cancel",type:"reset","aria-label":h,onClick:r.onClose},f))}var Pi=["_highlightResult","_snippetResult"];function tr(t){var e=t.key,n=t.limit,r=n===void 0?5:n,o=function(u){return function(){var s="__TEST_KEY__";try{return localStorage.setItem(s,""),localStorage.removeItem(s),!0}catch{return!1}}()===!1?{setItem:function(){},getItem:function(){return[]}}:{setItem:function(s){return window.localStorage.setItem(u,JSON.stringify(s))},getItem:function(){var s=window.localStorage.getItem(u);return s?JSON.parse(s):[]}}}(e),i=o.getItem().slice(0,r);return{add:function(u){var s=u,l=(s._highlightResult,s._snippetResult,ve(s,Pi)),f=i.findIndex(function(a){return a.objectID===l.objectID});f>-1&&i.splice(f,1),i.unshift(l),i=i.slice(0,r),o.setItem(i)},remove:function(u){i=i.filter(function(s){return s.objectID!==u.objectID}),o.setItem(i)},getAll:function(){return i}}}function Ii(t){var e,n="algoliasearch-client-js-".concat(t.key),r=function(){return e===void 0&&(e=t.localStorage||window.localStorage),e},o=function(){return JSON.parse(r().getItem(n)||"{}")},i=function(u){r().setItem(n,JSON.stringify(u))};return{get:function(u,s){var l=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{miss:function(){return Promise.resolve()}};return Promise.resolve().then(function(){(function(){var a=t.timeToLive?1e3*t.timeToLive:null,h=o(),y=Object.fromEntries(Object.entries(h).filter(function(v){return Ie(v,2)[1].timestamp!==void 0}));if(i(y),a){var d=Object.fromEntries(Object.entries(y).filter(function(v){var p=Ie(v,2)[1],m=new Date().getTime();return!(p.timestamp+a2&&arguments[2]!==void 0?arguments[2]:{miss:function(){return Promise.resolve()}};return o().then(function(u){return Promise.all([u,i.miss(u)])}).then(function(u){return Ie(u,1)[0]})},set:function(r,o){return Promise.resolve(o)},delete:function(r){return Promise.resolve()},clear:function(){return Promise.resolve()}}:{get:function(r,o){var i=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{miss:function(){return Promise.resolve()}};return n.get(r,o,i).catch(function(){return Me({caches:e}).get(r,o,i)})},set:function(r,o){return n.set(r,o).catch(function(){return Me({caches:e}).set(r,o)})},delete:function(r){return n.delete(r).catch(function(){return Me({caches:e}).delete(r)})},clear:function(){return n.clear().catch(function(){return Me({caches:e}).clear()})}}}function Lt(){var t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{serializable:!0},e={};return{get:function(n,r){var o=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{miss:function(){return Promise.resolve()}},i=JSON.stringify(n);if(i in e)return Promise.resolve(t.serializable?JSON.parse(e[i]):e[i]);var u=r(),s=o&&o.miss||function(){return Promise.resolve()};return u.then(function(l){return s(l)}).then(function(){return u})},set:function(n,r){return e[JSON.stringify(n)]=t.serializable?JSON.stringify(r):r,Promise.resolve(r)},delete:function(n){return delete e[JSON.stringify(n)],Promise.resolve()},clear:function(){return e={},Promise.resolve()}}}function Di(t){for(var e=t.length-1;e>0;e--){var n=Math.floor(Math.random()*(e+1)),r=t[e];t[e]=t[n],t[n]=r}return t}function Mr(t,e){return e&&Object.keys(e).forEach(function(n){t[n]=e[n](t)}),t}function Pt(t){for(var e=arguments.length,n=new Array(e>1?e-1:0),r=1;r0?r:void 0,timeout:n.timeout||e,headers:n.headers||{},queryParameters:n.queryParameters||{},cacheable:n.cacheable}}var ke={Read:1,Write:2,Any:3};function rr(t){var e=arguments.length>1&&arguments[1]!==void 0?arguments[1]:1;return N(N({},t),{},{status:e,lastUpdate:Date.now()})}function Hr(t){return typeof t=="string"?{protocol:"https",url:t,accept:ke.Any}:{protocol:t.protocol||"https",url:t.url,accept:t.accept||ke.Any}}var It="POST";function or(t,e,n,r){var o=[],i=function(y,d){if(y.method!=="GET"&&(y.data!==void 0||d.data!==void 0)){var v=Array.isArray(y.data)?y.data:N(N({},y.data),d.data);return JSON.stringify(v)}}(n,r),u=function(y,d){var v=N(N({},y.headers),d.headers),p={};return Object.keys(v).forEach(function(m){var g=v[m];p[m.toLowerCase()]=g}),p}(t,r),s=n.method,l=n.method!=="GET"?{}:N(N({},n.data),r.data),f=N(N(N({"x-algolia-agent":t.userAgent.value},t.queryParameters),l),r.queryParameters),a=0,h=function y(d,v){var p=d.pop();if(p===void 0)throw{name:"RetryError",message:"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.",transporterStackTrace:ir(o)};var m={data:i,headers:u,method:s,url:Ci(p,n.path,f),connectTimeout:v(a,t.timeouts.connect),responseTimeout:v(a,r.timeout)},g=function(b){var S={request:m,response:b,host:p,triesLeft:d.length};return o.push(S),S},_={onSuccess:function(b){return function(S){try{return JSON.parse(S.content)}catch(O){throw function(E,k){return{name:"DeserializationError",message:E,response:k}}(O.message,S)}}(b)},onRetry:function(b){var S=g(b);return b.isTimedOut&&a++,Promise.all([t.logger.info("Retryable failure",Fr(S)),t.hostsCache.set(p,rr(p,b.isTimedOut?3:2))]).then(function(){return y(d,v)})},onFail:function(b){throw g(b),function(S,O){var E=S.content,k=S.status,P=E;try{P=JSON.parse(E).message}catch{}return function(I,w,T){return{name:"ApiError",message:I,status:w,transporterStackTrace:T}}(P,k,O)}(b,ir(o))}};return t.requester.send(m).then(function(b){return function(S,O){return function(E){var k=E.status;return E.isTimedOut||function(P){var I=P.isTimedOut,w=P.status;return!I&&~~w==0}(E)||~~(k/100)!=2&&~~(k/100)!=4}(S)?O.onRetry(S):~~(S.status/100)==2?O.onSuccess(S):O.onFail(S)}(b,_)})};return function(y,d){return Promise.all(d.map(function(v){return y.get(v,function(){return Promise.resolve(rr(v))})})).then(function(v){var p=v.filter(function(_){return function(b){return b.status===1||Date.now()-b.lastUpdate>12e4}(_)}),m=v.filter(function(_){return function(b){return b.status===3&&Date.now()-b.lastUpdate<=12e4}(_)}),g=[].concat(_t(p),_t(m));return{getTimeout:function(_,b){return(m.length===0&&_===0?1:m.length+3+_)*b},statelessHosts:g.length>0?g.map(function(_){return Hr(_)}):d}})}(t.hostsCache,e).then(function(y){return h(_t(y.statelessHosts).reverse(),y.getTimeout)})}function ki(t){var e={value:"Algolia for JavaScript (".concat(t,")"),add:function(n){var r="; ".concat(n.segment).concat(n.version!==void 0?" (".concat(n.version,")"):"");return e.value.indexOf(r)===-1&&(e.value="".concat(e.value).concat(r)),e}};return e}function Ci(t,e,n){var r=Ur(n),o="".concat(t.protocol,"://").concat(t.url,"/").concat(e.charAt(0)==="/"?e.substr(1):e);return r.length&&(o+="?".concat(r)),o}function Ur(t){return Object.keys(t).map(function(e){return Pt("%s=%s",e,(n=t[e],Object.prototype.toString.call(n)==="[object Object]"||Object.prototype.toString.call(n)==="[object Array]"?JSON.stringify(t[e]):t[e]));var n}).join("&")}function ir(t){return t.map(function(e){return Fr(e)})}function Fr(t){var e=t.request.headers["x-algolia-api-key"]?{"x-algolia-api-key":"*****"}:{};return N(N({},t),{},{request:N(N({},t.request),{},{headers:N(N({},t.request.headers),e)})})}var Ai=function(t){return function(e,n){return e.method==="GET"?t.transporter.read(e,n):t.transporter.write(e,n)}},Br=function(t){return function(e){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};return Mr({transporter:t.transporter,appId:t.appId,indexName:e},n.methods)}},ar=function(t){return function(e,n){var r=e.map(function(o){return N(N({},o),{},{params:Ur(o.params||{})})});return t.transporter.read({method:It,path:"1/indexes/*/queries",data:{requests:r},cacheable:!0},n)}},cr=function(t){return function(e,n){return Promise.all(e.map(function(r){var o=r.params,i=o.facetName,u=o.facetQuery,s=function(l,f){if(l==null)return{};var a,h,y=function(v,p){if(v==null)return{};var m,g,_={},b=Object.keys(v);for(g=0;g=0||(_[m]=v[m]);return _}(l,f);if(Object.getOwnPropertySymbols){var d=Object.getOwnPropertySymbols(l);for(h=0;h=0||Object.prototype.propertyIsEnumerable.call(l,a)&&(y[a]=l[a])}return y}(o,mo);return Br(t)(r.indexName,{methods:{searchForFacetValues:Vr}}).searchForFacetValues(i,u,N(N({},n),s))}))}},xi=function(t){return function(e,n,r){return t.transporter.read({method:It,path:Pt("1/answers/%s/prediction",t.indexName),data:{query:e,queryLanguages:n},cacheable:!0},r)}},Ni=function(t){return function(e,n){return t.transporter.read({method:It,path:Pt("1/indexes/%s/query",t.indexName),data:{query:e},cacheable:!0},n)}},Vr=function(t){return function(e,n,r){return t.transporter.read({method:It,path:Pt("1/indexes/%s/facets/%s/query",t.indexName,e),data:{facetQuery:n},cacheable:!0},r)}};function Kr(t,e,n){var r={appId:t,apiKey:e,timeouts:{connect:1,read:2,write:30},requester:{send:function(o){return new Promise(function(i){var u=new XMLHttpRequest;u.open(o.method,o.url,!0),Object.keys(o.headers).forEach(function(a){return u.setRequestHeader(a,o.headers[a])});var s,l=function(a,h){return setTimeout(function(){u.abort(),i({status:0,content:h,isTimedOut:!0})},1e3*a)},f=l(o.connectTimeout,"Connection timeout");u.onreadystatechange=function(){u.readyState>u.OPENED&&s===void 0&&(clearTimeout(f),s=l(o.responseTimeout,"Socket timeout"))},u.onerror=function(){u.status===0&&(clearTimeout(f),clearTimeout(s),i({content:u.responseText||"Network request failed",status:u.status,isTimedOut:!1}))},u.onload=function(){clearTimeout(f),clearTimeout(s),i({content:u.responseText,status:u.status,isTimedOut:!1})},u.send(o.data)})}},logger:{debug:function(o,i){return Promise.resolve()},info:function(o,i){return Promise.resolve()},error:function(o,i){return console.error(o,i),Promise.resolve()}},responsesCache:Lt(),requestsCache:Lt({serializable:!1}),hostsCache:Me({caches:[Ii({key:"4.19.1-".concat(t)}),Lt()]}),userAgent:ki("4.19.1").add({segment:"Browser",version:"lite"}),authMode:0};return function(o){var i=o.appId,u=function(f,a,h){var y={"x-algolia-api-key":h,"x-algolia-application-id":a};return{headers:function(){return f===1?y:{}},queryParameters:function(){return f===0?y:{}}}}(o.authMode!==void 0?o.authMode:1,i,o.apiKey),s=function(f){var a=f.hostsCache,h=f.logger,y=f.requester,d=f.requestsCache,v=f.responsesCache,p=f.timeouts,m=f.userAgent,g=f.hosts,_=f.queryParameters,b={hostsCache:a,logger:h,requester:y,requestsCache:d,responsesCache:v,timeouts:p,userAgent:m,headers:f.headers,queryParameters:_,hosts:g.map(function(S){return Hr(S)}),read:function(S,O){var E=nr(O,b.timeouts.read),k=function(){return or(b,b.hosts.filter(function(I){return(I.accept&ke.Read)!=0}),S,E)};if((E.cacheable!==void 0?E.cacheable:S.cacheable)!==!0)return k();var P={request:S,mappedRequestOptions:E,transporter:{queryParameters:b.queryParameters,headers:b.headers}};return b.responsesCache.get(P,function(){return b.requestsCache.get(P,function(){return b.requestsCache.set(P,k()).then(function(I){return Promise.all([b.requestsCache.delete(P),I])},function(I){return Promise.all([b.requestsCache.delete(P),Promise.reject(I)])}).then(function(I){var w=Ie(I,2);return w[0],w[1]})})},{miss:function(I){return b.responsesCache.set(P,I)}})},write:function(S,O){return or(b,b.hosts.filter(function(E){return(E.accept&ke.Write)!=0}),S,nr(O,b.timeouts.write))}};return b}(N(N({hosts:[{url:"".concat(i,"-dsn.algolia.net"),accept:ke.Read},{url:"".concat(i,".algolia.net"),accept:ke.Write}].concat(Di([{url:"".concat(i,"-1.algolianet.com")},{url:"".concat(i,"-2.algolianet.com")},{url:"".concat(i,"-3.algolianet.com")}]))},o),{},{headers:N(N({},u.headers()),{},{"content-type":"application/x-www-form-urlencoded"},o.headers),queryParameters:N(N({},u.queryParameters()),o.queryParameters)})),l={transporter:s,appId:i,addAlgoliaAgent:function(f,a){s.userAgent.add({segment:f,version:a})},clearCache:function(){return Promise.all([s.requestsCache.clear(),s.responsesCache.clear()]).then(function(){})}};return Mr(l,o.methods)}(N(N(N({},r),n),{},{methods:{search:ar,searchForFacetValues:cr,multipleQueries:ar,multipleSearchForFacetValues:cr,customRequest:Ai,initIndex:function(o){return function(i){return Br(o)(i,{methods:{search:Ni,searchForFacetValues:Vr,findAnswers:xi}})}}}}))}Kr.version="4.19.1";var Ti=["footer","searchBox"];function Ri(t){var e=t.appId,n=t.apiKey,r=t.indexName,o=t.placeholder,i=o===void 0?"Search docs":o,u=t.searchParameters,s=t.maxResultsPerGroup,l=t.onClose,f=l===void 0?yi:l,a=t.transformItems,h=a===void 0?er:a,y=t.hitComponent,d=y===void 0?ni:y,v=t.resultsFooterComponent,p=v===void 0?function(){return null}:v,m=t.navigator,g=t.initialScrollY,_=g===void 0?0:g,b=t.transformSearchClient,S=b===void 0?er:b,O=t.disableUserPersonalization,E=O!==void 0&&O,k=t.initialQuery,P=k===void 0?"":k,I=t.translations,w=I===void 0?{}:I,T=t.getMissingResultsUrl,M=t.insights,C=M!==void 0&&M,z=w.footer,ae=w.searchBox,at=ve(w,Ti),de=be(c.useState({query:"",collections:[],completion:null,context:{},isOpen:!1,activeItemId:null,status:"idle"}),2),H=de[0],he=de[1],J=c.useRef(null),Z=c.useRef(null),L=c.useRef(null),ne=c.useRef(null),$=c.useRef(null),V=c.useRef(10),ce=c.useRef(typeof window<"u"?window.getSelection().toString().slice(0,64):"").current,Q=c.useRef(P||ce).current,Se=function(A,R,U){return c.useMemo(function(){var W=Kr(A,R);return W.addAlgoliaAgent("docsearch","3.6.1"),/docsearch.js \(.*\)/.test(W.transporter.userAgent.value)===!1&&W.addAlgoliaAgent("docsearch-react","3.6.1"),U(W)},[A,R,U])}(e,n,S),ue=c.useRef(tr({key:"__DOCSEARCH_FAVORITE_SEARCHES__".concat(r),limit:10})).current,G=c.useRef(tr({key:"__DOCSEARCH_RECENT_SEARCHES__".concat(r),limit:ue.getAll().length===0?7:4})).current,Y=c.useCallback(function(A){if(!E){var R=A.type==="content"?A.__docsearch_parent:A;R&&ue.getAll().findIndex(function(U){return U.objectID===R.objectID})===-1&&G.add(R)}},[ue,G,E]),ct=c.useCallback(function(A){if(H.context.algoliaInsightsPlugin&&A.__autocomplete_id){var R=A,U={eventName:"Item Selected",index:R.__autocomplete_indexName,items:[R],positions:[A.__autocomplete_id],queryID:R.__autocomplete_queryID};H.context.algoliaInsightsPlugin.insights.clickedObjectIDsAfterSearch(U)}},[H.context.algoliaInsightsPlugin]),le=c.useMemo(function(){return Xo({id:"docsearch",defaultActiveItemId:0,placeholder:i,openOnFocus:!0,initialState:{query:Q,context:{searchSuggestions:[]}},insights:C,navigator:m,onStateChange:function(A){he(A.state)},getSources:function(A){var R=A.query,U=A.state,W=A.setContext,se=A.setStatus;if(!R)return E?[]:[{sourceId:"recentSearches",onSelect:function(q){var X=q.item,Ne=q.event;Y(X),gt(Ne)||f()},getItemUrl:function(q){return q.item.url},getItems:function(){return G.getAll()}},{sourceId:"favoriteSearches",onSelect:function(q){var X=q.item,Ne=q.event;Y(X),gt(Ne)||f()},getItemUrl:function(q){return q.item.url},getItems:function(){return ue.getAll()}}];var fe=!!C;return Se.search([{query:R,indexName:r,params:Fe({attributesToRetrieve:["hierarchy.lvl0","hierarchy.lvl1","hierarchy.lvl2","hierarchy.lvl3","hierarchy.lvl4","hierarchy.lvl5","hierarchy.lvl6","content","type","url"],attributesToSnippet:["hierarchy.lvl1:".concat(V.current),"hierarchy.lvl2:".concat(V.current),"hierarchy.lvl3:".concat(V.current),"hierarchy.lvl4:".concat(V.current),"hierarchy.lvl5:".concat(V.current),"hierarchy.lvl6:".concat(V.current),"content:".concat(V.current)],snippetEllipsisText:"โ€ฆ",highlightPreTag:"",highlightPostTag:"",hitsPerPage:20,clickAnalytics:fe},u)}]).catch(function(q){throw q.name==="RetryError"&&se("error"),q}).then(function(q){var X=q.results[0],Ne=X.hits,Jr=X.nbHits,Dt=Xn(Ne,function(kt){return Lr(kt)},s);U.context.searchSuggestions.length0&&(en(),$.current&&$.current.focus())},[Q,en]),c.useEffect(function(){function A(){if(Z.current){var R=.01*window.innerHeight;Z.current.style.setProperty("--docsearch-vh","".concat(R,"px"))}}return A(),window.addEventListener("resize",A),function(){window.removeEventListener("resize",A)}},[]),c.createElement("div",B({ref:J},zr({"aria-expanded":!0}),{className:["DocSearch","DocSearch-Container",H.status==="stalled"&&"DocSearch-Container--Stalled",H.status==="error"&&"DocSearch-Container--Errored"].filter(Boolean).join(" "),role:"button",tabIndex:0,onMouseDown:function(A){A.target===A.currentTarget&&f()}}),c.createElement("div",{className:"DocSearch-Modal",ref:Z},c.createElement("header",{className:"DocSearch-SearchBar",ref:L},c.createElement(ji,B({},le,{state:H,autoFocus:Q.length===0,inputRef:$,isFromSelection:!!Q&&Q===ce,translations:ae,onClose:f}))),c.createElement("div",{className:"DocSearch-Dropdown",ref:ne},c.createElement(wi,B({},le,{indexName:r,state:H,hitComponent:d,resultsFooterComponent:p,disableUserPersonalization:E,recentSearches:G,favoriteSearches:ue,inputRef:$,translations:at,getMissingResultsUrl:T,onItemClick:function(A,R){ct(A),Y(A),gt(R)||f()}}))),c.createElement("footer",{className:"DocSearch-Footer"},c.createElement(ti,{translations:z}))))}function qi(t){var e,n,r=c.useRef(null),o=be(c.useState(!1),2),i=o[0],u=o[1],s=be(c.useState((t==null?void 0:t.initialQuery)||void 0),2),l=s[0],f=s[1],a=c.useCallback(function(){u(!0)},[u]),h=c.useCallback(function(){u(!1)},[u]);return function(y){var d=y.isOpen,v=y.onOpen,p=y.onClose,m=y.onInput,g=y.searchButtonRef;c.useEffect(function(){function _(b){var S;(b.keyCode===27&&d||((S=b.key)===null||S===void 0?void 0:S.toLowerCase())==="k"&&(b.metaKey||b.ctrlKey)||!function(O){var E=O.target,k=E.tagName;return E.isContentEditable||k==="INPUT"||k==="SELECT"||k==="TEXTAREA"}(b)&&b.key==="/"&&!d)&&(b.preventDefault(),d?p():document.body.classList.contains("DocSearch--active")||document.body.classList.contains("DocSearch--active")||v()),g&&g.current===document.activeElement&&m&&/[a-zA-Z0-9]/.test(String.fromCharCode(b.keyCode))&&m(b)}return window.addEventListener("keydown",_),function(){window.removeEventListener("keydown",_)}},[d,v,p,m,g])}({isOpen:i,onOpen:a,onClose:h,onInput:c.useCallback(function(y){u(!0),f(y.key)},[u,f]),searchButtonRef:r}),c.createElement(c.Fragment,null,c.createElement(yo,{ref:r,translations:t==null||(e=t.translations)===null||e===void 0?void 0:e.button,onClick:a}),i&&Er(c.createElement(Ri,B({},t,{initialScrollY:window.scrollY,initialQuery:l,translations:t==null||(n=t.translations)===null||n===void 0?void 0:n.modal,onClose:h})),document.body))}function Li(t){Pr(c.createElement(qi,Mt({},t,{transformSearchClient:function(e){return e.addAlgoliaAgent("docsearch.js","3.6.1"),t.transformSearchClient?t.transformSearchClient(e):e}})),function(e){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:window;return typeof e=="string"?n.document.querySelector(e):e}(t.container,t.environment))}export{Li as default}; diff --git a/assets/index.html-Ci232zr-.js b/assets/index.html-Ci232zr-.js new file mode 100644 index 000000000..d144f71f2 --- /dev/null +++ b/assets/index.html-Ci232zr-.js @@ -0,0 +1,35 @@ +import{_ as c}from"./texture-compression-BuEaeBZn.js";import{_ as g,r as l,o as m,c as y,e as a,b as t,w as r,a as e,d as s}from"./app-CRZRGfEE.js";const u="/docs/blender/logo.png",C="/docs/blender/settings.webp",b="/docs/blender/project-panel.webp",F="/docs/blender/project-panel-2.webp",E="/docs/blender/project-panel-3.webp",f="/docs/blender/settings-color-management.webp",B="/docs/blender/environment.webp",w="/docs/blender/environment-camera.webp",v="/docs/blender/dont-export.webp",x="/docs/blender/animatorcontroller-open.webp",D="/docs/blender/animatorcontroller-overview.webp",A="/docs/blender/animatorcontroller-assigning.webp",j="/docs/blender/timeline_setup.webp",T="/docs/blender/timeline.webp",_="/docs/blender/components-panel.webp",N="/docs/blender/components-panel-select.webp",P="/docs/blender/remove-component.webp",S="/docs/blender/lightmapping-object.webp",R="/docs/blender/lightmapping-scene-panel.webp",I="/docs/blender/lightmapping-panel.webp",L="/docs/blender/updates.webp",Y="/docs/blender/bugreporter.webp",M={};function U(q,i){const h=l("os-link"),p=l("ClientOnly"),d=l("needle-button"),k=l("NoDownloadYet"),n=l("video-embed"),o=l("RouteLink");return m(),y("div",null,[i[18]||(i[18]=a('

    Needle Engine for Blender

    Install the Blender Add-on

    ',4)),t(p,null,{default:r(()=>[e("p",null,[i[1]||(i[1]=s("Make sure you have installed ")),i[2]||(i[2]=e("a",{target:"_blank",href:"https://www.blender.org/download/"},[e("strong",null,"Blender"),s(" 4.0, 4.1 or 4.2")],-1)),i[3]||(i[3]=s(" and ")),t(h,{windows_url:"https://nodejs.org/dist/v20.9.0/node-v20.9.0-x64.msi",osx_url:"https://nodejs.org/dist/v20.9.0/node-v20.9.0.pkg"},{default:r(()=>i[0]||(i[0]=[e("strong",null,"node.js",-1)])),_:1}),i[4]||(i[4]=s("."))])]),_:1}),t(k,null,{default:r(()=>[t(d,{event_goal:"download_blender",event_position:"getting_started",large:"",href:"https://engine.needle.tools/downloads/blender?utm_source=needle_docs&utm_content=getting_started",same_tab:"",next_url:"/docs/blender/"},{default:r(()=>i[5]||(i[5]=[e("strong",null,"Download Needle Engine for Blender",-1)])),_:1})]),_:1}),i[19]||(i[19]=a('
    1. In Blender, go to File > Settings > Add-ons and click the Install button.

    2. Select the downloaded zip file (named needle-blender-plugin-*.zip) to install it.

    3. Search for "Needle" in the Add-ons search bar and make sure `Needle Engine.

    Settings

    Getting Started

    Thank you for using Needle Engine for Blender.

    With this add-on you can create highly interactive and optimized WebGL and WebXR experiences inside Blender, that run using Needle Engine and three.js.

    You'll be able to sequence animations, easily lightmap your scenes, add interactivity or create your own scripts written in Typescript or Javascript that run on the web.

    ',6)),t(n,{src:"/docs/blender/environment-light.mp4"}),i[20]||(i[20]=a('

    Matching lighting and environment settings between Blender and Needle Engine. HDRI environment lights are automatically exported, directly from Blender. Once you save, the page is automatically reloaded.

    Providing Feedback

    Your feedback is invaluable when it comes to deciding which features and workflows we should prioritize. If you have feedback for us (good or bad), please let us know in the forum!

    Samples for Blender

    First create or open a new blend file that you want to be exported to the web.
    Open the Properties window open the scene category. Select a Project Path in the Needle Engine panel. Then click Generate Project. It will automatically install and start the server - once it has finished your browser should open and the threejs scene will load.

    Project panel

    By default your scene will automatically re-exported when you save the blend file.
    If the local server is running (e.g. by clicking Run Project) the website will automatically refresh with your changed model.

    When your web project already exists and you just want to continue working on the website
    click the blue Run Project button to start the local server:
    Project panel

    Project Panel overview

    Project panel

    1. The path to your web project. You can use the little folder button on the right to select a different path.
    2. The Run Project button shows up when the Project path shows to a valid web project. A web project is valid when it contains a package.json
    3. Directory open the directory of your web project (the Project Path)
    4. This button re-exports the current scene as a glb to your local web project. This also happens by default when saving your blend file.
    5. Code Editor tries to open the vscode workspace in your web project
    6. If you work with multiple scenes in one blend file, you can configure which scene is your Main scene and should be exported to the web. If any of your components references another scene they will also be exported as separate glb files. When clicking the "Export" button, your Main scene will be the one that's loaded in the browser.
    7. Use the Build: Development or Build: Production buttons when you want to upload your web project to a server. This will bundle your web project and produce the files that you can upload. When clicking Build: Production it will also apply optimization to your textures (they will be compressed for the web)
    8. Open the documentation

    Blender Settings

    Color Management

    By default the blender viewport is set to Filmic - with this setting your colors in Blender and in three.js will not match. To fix this go to the Blender Render category and in the ColorManagement panel select View Transform: Standard

    Correct color management settings

    Environment Lighting

    You can change the environment lighting and skybox using the Viewport shading options.
    Assign a cubemap to use for lighting or the background skybox. You can adjust the strength or blur to modify the appearance to your liking.

    Note: To also see the skybox cubemap in the browser increase the World Opacity to 1.

    Note: Alternatively you can enable the Scene World setting in the Viewport Shading tab to use the environment texture assigned in the blender world settings.

    Environment

    ',20)),t(n,{limit_height:"",max_height:"300px",src:"/docs/blender/environment.mp4"}),i[21]||(i[21]=e("p",null,[s("Alternatively if you don't want to see the cubemap as a background add a Camera component to your Blender Camera and change "),e("code",null,"clearFlags: SolidColor"),s(" - note that the Camera "),e("code",null,"backgroundBlurriness"),s(" and "),e("code",null,"backgroundIntensity"),s(" settings override the Viewport shading settings.")],-1)),i[22]||(i[22]=e("p",null,[e("img",{src:w,alt:"Environment Camera"})],-1)),i[23]||(i[23]=e("h3",{id:"add-your-custom-hdri-exr-environment-lighting-and-skybox",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#add-your-custom-hdri-exr-environment-lighting-and-skybox"},[e("span",null,"Add your custom HDRI / EXR environment lighting and skybox")])],-1)),t(n,{limit_height:"",src:"/docs/blender/custom_hdri.mp4"}),i[24]||(i[24]=a('

    Export

    To exclude an object from being exported you can disable the Viewport and the Render display (see image below)

    Exclude from export

    Animation ๐Ÿ‡

    For simple usecases you can use the Animation component for playback of one or multiple animationclips.
    Just select your object, add an Animation component and assign the clip (you can add additional clips to be exported to the clips array.
    By default it will only playback the first clip assigned when playAutomatically is enabled. You can trigger the other clips using a simple custom typescript component)

    ',6)),t(n,{limit_height:"",src:"/docs/blender/animation.mp4"}),i[25]||(i[25]=s()),i[26]||(i[26]=e("h3",{id:"animatorcontroller",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#animatorcontroller"},[e("span",null,"AnimatorController")])],-1)),i[27]||(i[27]=e("p",null,"The animator controller can be created for more complex scenarios. It works as a statemachine which allows you to create multiple animation states in a graph and configure conditions and interpolation settings for transitioning between those.",-1)),t(n,{src:"/docs/blender/animatorcontroller-web.mp4"}),i[28]||(i[28]=e("p",null,[e("em",null,[s("Create and export "),e("a",{href:"#animatorcontroller"},"animator statemachines"),s(" for controlling complex character animations")])],-1)),i[29]||(i[29]=e("h4",{id:"creating-an-animatorcontroller",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#creating-an-animatorcontroller"},[e("span",null,"Creating an AnimatorController")])],-1)),i[30]||(i[30]=e("p",null,"The AnimatorController editor can be opened using the EditorType dropdown in the topleft corner of each panel:",-1)),i[31]||(i[31]=e("p",null,[e("img",{src:x,alt:"AnimatorController open window"})],-1)),t(n,{limit_height:"",max_height:"188px",src:"/docs/blender/animatorcontroller-create.mp4"}),i[32]||(i[32]=a('

    Creating a new animator-controller asset โ˜ or select one from your previously created assets

    Graph overview

    AnimatorController overview

    1. Use Shift+A to create a new AnimatorState
    2. The Parameters node will be created once you add a first node. Select it to setup parameters to be used in transitions (via the Node panel on the right border)
    3. This is an AnimatorState. the orange state is the start state (it can be changed using the Set default state button in the Node/Properties panel)
    4. The Properties for an AnimatorState can be used to setup one or multiple transitions to other states. Use the Conditions array to select parameters that must match the condition for doing the transition.

    Using an AnimatorController

    To use an AnimatorController add an Animator component to the root object of your animations and select the AnimatorController asset that you want to use for this object.

    AnimatorController assign to animator

    You can set the Animator parameters from typescript or by e.g. using the event of a Button component

    Timeline โ€” NLA Tracks export ๐ŸŽฌ

    You can export Blender NLA tracks directly to the web.
    Add a PlayableDirector component (via Add Component) to a any blender object. Assign the objects in the animation tracks list in the component for which you want the NLA tracks to be exported.


    Code example for interactive timeline playback

    Add this script to src/scripts (see custom components section) and add it to any object in Blender to make a timeline's time be controlled by scrolling in the browsers

    import { Behaviour, PlayableDirector, serializable, Mathf } from "@needle-tools/engine";
    +
    +export class ScrollTimeline extends Behaviour {
    +
    +    @serializable(PlayableDirector)
    +    timeline?: PlayableDirector;
    +
    +    @serializable()
    +    sensitivity: number = .5;
    +
    +    @serializable()
    +    clamp: boolean = false;
    +
    +    private _targetTime: number = 0;
    +
    +    awake() {
    +        this.context.domElement.addEventListener("wheel", this.onWheel);
    +        if (this.timeline) this.timeline.pause();
    +    }
    +
    +    private onWheel = (e: WheelEvent) => {
    +        if (this.timeline) {
    +            this._targetTime = this.timeline.time + e.deltaY * 0.01 * this.sensitivity;
    +            if (this.clamp) this._targetTime = Mathf.clamp(this._targetTime, 0, this.timeline.duration);
    +        }
    +    }
    +
    +    update(): void {
    +        if (!this.timeline) return;
    +        const time = Mathf.lerp(this.timeline.time, this._targetTime, this.context.time.deltaTime / .3);
    +        this.timeline.time = time;
    +        this.timeline.pause();
    +        this.timeline.evaluate();
    +    }
    +}

    Interactivity ๐Ÿ˜Ž

    You can add or remove components to objects in your hierarchy using the Needle Components panel:

    Component panel

    Component panel
    For example by adding an OrbitControls component to the camera object
    you get basic camera controls for mobile and desktop devicesAdjust settings for each component in their respective panels

    Components can be removed using the X button in the lower right:

    Remove component

    Custom Components

    Custom components can also be easily added by simply writing Typescript classes. They will automatically compile and show up in Blender when saved.

    To create custom components open the workspace via the Needle Project panel and add a .ts script file in src/scripts inside your web project. Please refer to the scripting documentation to learn how to write custom components for Needle Engine.

    Note

    Make sure @needle-tools/needle-component-compiler 2.x is installed in your web project (package.json devDependencies)

    Lightmapping ๐Ÿ’ก

    Needle includes a lightmapping plugin that makes it very easy to bake beautiful lights to textures and bring them to the web. The plugin will automatically generate lightmap UVs for all models marked to be lightmapped, there is no need to make a manual texture atlas. It also supports lightmapping of multiple instances with their own lightmap data. For lightmapping to work, you need at least one light and one object with Lightmapped turned on in the Needle Object panel.

    ',25)),t(n,{limit_height:"",max_height:"800px",src:"/docs/blender/lightmapping.mp4"}),i[33]||(i[33]=a('

    Tips

    You can download the .blend file from the video here.

    Use the Needle Object panel to enable lightmapping for a mesh object or light:

    Lightmapping object

    For quick access to lightmap settings and baking options you can use the scene view panel in the Needle tab:

    Lightmapping scene panel

    Alternatively you can also use the Lightmapping panel in the Render Properties tab:

    Lightmapping object

    Experimental Feature

    The lightmapping plugin is experimental. We recommend creating a backup of your .blend file when using it. Please report problems or errors you encounter in our forum ๐Ÿ™

    Texture Compression

    ',10)),e("p",null,[i[9]||(i[9]=s("The Needle Engine Build Pipeline automatically compresses textures using ECT1S and UASTC (depending on their usage in materials) when making a production build (")),e("strong",null,[i[7]||(i[7]=s("requires ")),t(o,{to:"/getting-started/#install-these-tools-for-production-builds"},{default:r(()=>i[6]||(i[6]=[s("toktx")])),_:1}),i[8]||(i[8]=s(" being installed"))]),i[10]||(i[10]=s("). But you can override or change the compression type per texture in the Material panel."))]),e("p",null,[i[12]||(i[12]=s("You can modify the compression that is being applied per texture. To override the default compression settings go to the ")),i[13]||(i[13]=e("code",null,"Material",-1)),i[14]||(i[14]=s(" tab and open the ")),i[15]||(i[15]=e("code",null,"Needle Material Settings",-1)),i[16]||(i[16]=s(". There you will find a toggle to override the texture settings per texture used in your material. See the ")),t(o,{to:"/deployment.html#how-do-i-choose-between-etc1s-uastc-and-webp-compression"},{default:r(()=>i[11]||(i[11]=[s("texture compression table")])),_:1}),i[17]||(i[17]=s(" for a brief overview over the differences between each compression algorithm."))]),i[34]||(i[34]=a('

    Texture Compression options in Blender

    Updating

    The lightbulb in the Needle Project panel informs you when a new version of the addon is available.
    Simply click the icon to download the new version.
    Update notification

    Reporting an issue

    If you run into any problems we're more than happy to help! Please join our discord for fast support.

    Please also check the logs in Blender. You can find logs specific to the Needle Engine Addon via Help/Needle in Blender.

    Integrated Bug Reporter

    Needle Blender Bug Reporter panel
    You can also automatically create and upload a bugreport directly from Blender. Uploaded bugreports will solely be used for debugging. They are encrypted on our backend and will be deleted after 30 days.

    If needed, in certain cases we're also able to set up custom NDAs for your projects. Please contact us for more information.

    Using the Bug Reporter requires a web project

    Make sure you've set up a web project before sending a bug report โ€“ it will allow us to understand more about your system and setup and make it easier to reproduce the issue.

    ',10))])}const V=g(M,[["render",U],["__file","index.html.vue"]]),z=JSON.parse('{"path":"/blender/","title":"Needle Engine for Blender","lang":"en-US","frontmatter":{"title":"Needle Engine for Blender","editLink":true,"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/preview.jpeg"}],["meta",{"name":"og:description","content":"---"}]],"description":"---"},"headers":[{"level":2,"title":"Install the Blender Add-on","slug":"install-the-blender-add-on","link":"#install-the-blender-add-on","children":[]},{"level":2,"title":"Getting Started","slug":"getting-started","link":"#getting-started","children":[]},{"level":2,"title":"Samples for Blender","slug":"samples-for-blender","link":"#samples-for-blender","children":[{"level":3,"title":"Project Panel overview","slug":"project-panel-overview","link":"#project-panel-overview","children":[]}]},{"level":2,"title":"Blender Settings","slug":"blender-settings","link":"#blender-settings","children":[{"level":3,"title":"Color Management","slug":"color-management","link":"#color-management","children":[]}]},{"level":2,"title":"Environment Lighting","slug":"environment-lighting","link":"#environment-lighting","children":[{"level":3,"title":"Add your custom HDRI / EXR environment lighting and skybox","slug":"add-your-custom-hdri-exr-environment-lighting-and-skybox","link":"#add-your-custom-hdri-exr-environment-lighting-and-skybox","children":[]}]},{"level":2,"title":"Export","slug":"export","link":"#export","children":[]},{"level":2,"title":"Animation ๐Ÿ‡","slug":"animation","link":"#animation","children":[{"level":3,"title":"AnimatorController","slug":"animatorcontroller","link":"#animatorcontroller","children":[]},{"level":3,"title":"Timeline โ€” NLA Tracks export ๐ŸŽฌ","slug":"timeline-nla-tracks-export","link":"#timeline-nla-tracks-export","children":[]}]},{"level":2,"title":"Interactivity ๐Ÿ˜Ž","slug":"interactivity","link":"#interactivity","children":[{"level":3,"title":"Custom Components","slug":"custom-components","link":"#custom-components","children":[]}]},{"level":2,"title":"Lightmapping ๐Ÿ’ก","slug":"lightmapping","link":"#lightmapping","children":[]},{"level":2,"title":"Texture Compression","slug":"texture-compression","link":"#texture-compression","children":[]},{"level":2,"title":"Updating","slug":"updating","link":"#updating","children":[]},{"level":2,"title":"Reporting an issue","slug":"reporting-an-issue","link":"#reporting-an-issue","children":[{"level":3,"title":"Integrated Bug Reporter","slug":"integrated-bug-reporter","link":"#integrated-bug-reporter","children":[]}]}],"git":{"updatedTime":1727182460000},"filePathRelative":"blender/index.md"}');export{V as comp,z as data}; diff --git a/assets/index.html-CxWg-amX.js b/assets/index.html-CxWg-amX.js new file mode 100644 index 000000000..09003bf5b --- /dev/null +++ b/assets/index.html-CxWg-amX.js @@ -0,0 +1 @@ +import{_ as g,r as a,o as m,c as f,e as c,b as n,w as i,a as e,d as o}from"./app-CRZRGfEE.js";const h="/docs/imgs/banner.webp",b={};function w(y,t){const r=a("quoteslides"),s=a("action"),l=a("actiongroup"),d=a("copyright"),u=a("removeserviceworker"),p=a("ClientOnly");return m(),f("div",null,[t[6]||(t[6]=c('

    Needle Engine is a web engine for complex and simple 3D applications alike. Work on your machine and deploy anywhere. Needle Engine is flexible, extensible and has built-in support for collaboration and XR. It is built around the glTF standard for 3D assets.

    Powerful integrations for Unity and Blender allow artists and developers to collaborate and manage web applications inside battle-tested 3d editors. These Integrations allow you to use editor features for creating models, authoring materials, animating and sequencing animations, baking lightmaps and more with ease.

    Our powerful compression and optimization pipeline for the web make sure your files are ready, small and load fast.

    ',4)),n(r,null,{default:i(()=>t[0]||(t[0]=[e("div",null,[o("Unbelievable Unity editor integration by an order of magnitude,"),e("br"),o("and as straightforward as the docs claim. Wow. โ€” Chris Mahoney")],-1),e("div",null,"This is the best thing I have seen after cinemachine in Unity โ€” Rinesh Thomas",-1),e("div",null,[o("Spent the last 2.5 months building this game, never built a game or used Unity before"),e("br"),o("but absolutely loving the whole process. So rapid! โ€” Matthew Pieri")],-1),e("div",null,[e("a",{href:"https://needle.tools?utm_source=needle_docs&utm_content=quote"},"needle.tools"),o(" is a wonderful showcase of what Needle contributes to 3D via the web. I just love it. โ€” Kevin Curry")],-1),e("div",null,"Played with this a bit this morning ๐Ÿคฏ๐Ÿคฏ pretty magical โ€” Brit Gardner",-1),e("div",null,"This is huge for WebXR and shared, immersive 3D experiences! The AR part worked flawlessly on my Samsung S21. โ€” Marc Wakefield",-1),e("div",null,"This is amazing and if you are curious about WebXR with Unity this will help us get there โ€” Dilmer Valecillos",-1),e("div",null,"We just gotta say WOW ๐Ÿคฉ โ€” Unity for Digital Twins",-1)])),_:1}),n(l,null,{default:i(()=>[n(s,{href:"getting-started/"},{default:i(()=>t[1]||(t[1]=[o(" Get started โญ ")])),_:1}),n(s,{href:"features-overview"},{default:i(()=>t[2]||(t[2]=[o(" Features ๐ŸŽจ ")])),_:1}),n(s,{href:"https://engine.needle.tools/samples?utm_source=needle_docs&utm_content=actionbutton"},{default:i(()=>t[3]||(t[3]=[o(" Samples ๐Ÿ‘“ ")])),_:1}),n(s,{subtitle:"with AI support",href:"https://forum.needle.tools?utm_source=needle_docs&utm_content=actionbutton"},{default:i(()=>t[4]||(t[4]=[o(" Get Help ๐Ÿ’ฌ ")])),_:1})]),_:1}),t[7]||(t[7]=e("br",null,null,-1)),t[8]||(t[8]=e("br",null,null,-1)),n(l,null,{default:i(()=>t[5]||(t[5]=[e("p",null,[e("a",{class:"no-external-link-icon",href:"https://www.npmjs.com/package/@needle-tools/engine"},[e("img",{src:"https://img.shields.io/npm/v/@needle-tools/engine?style=flat&colorA=ddd&colorB=ddd"})])],-1),e("p",null,[e("a",{class:"no-external-link-icon",href:"https://engine.needle.tools/docs/getting-started/"},[e("img",{src:"https://img.shields.io/npm/dt/@needle-tools/engine.svg?style=flat&colorA=ddd&colorB=ddd"})])],-1),e("p",null,[e("a",{class:"no-external-link-icon",href:"https://discord.needle.tools"},[e("img",{src:"https://img.shields.io/discord/717429793926283276?style=flat&colorA=ddd&colorB=ddd&label=discord&logo=discord&logoColor=ffffff"})])],-1)])),_:1}),t[9]||(t[9]=e("p",null,null,-1)),n(d),n(p,null,{default:i(()=>[n(u)]),_:1})])}const k=g(b,[["render",w],["__file","index.html.vue"]]),x=JSON.parse('{"path":"/","title":"","lang":"en-US","frontmatter":{"next":"./getting-started/index.md","sidebar":false,"editLink":false,"lastUpdated":false,"footer":"Copyright ยฉ 2024 Needle Tools GmbH","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/needle engine.png"}],["meta",{"name":"og:description","content":"---\\nNeedle Engine is a web engine for complex and simple 3D applications alike. Work on your machine and deploy anywhere. Needle Engine is flexible, extensible and has built-in support for collaboration and XR. It is built around the glTF standard for 3D assets.\\nPowerful integrations for Unity and Blender allow artists and developers to collaborate and manage web applications inside battle-tested 3d editors. These Integrations allow you to use editor features for creating models, authoring materials, animating and sequencing animations, baking lightmaps and more with ease.\\nOur powerful compression and optimization pipeline for the web make sure your files are ready, small and load fast."}]],"description":"---\\nNeedle Engine is a web engine for complex and simple 3D applications alike. Work on your machine and deploy anywhere. Needle Engine is flexible, extensible and has built-in support for collaboration and XR. It is built around the glTF standard for 3D assets.\\nPowerful integrations for Unity and Blender allow artists and developers to collaborate and manage web applications inside battle-tested 3d editors. These Integrations allow you to use editor features for creating models, authoring materials, animating and sequencing animations, baking lightmaps and more with ease.\\nOur powerful compression and optimization pipeline for the web make sure your files are ready, small and load fast."},"headers":[],"git":{"updatedTime":1727191885000},"filePathRelative":"index.md"}');export{k as comp,x as data}; diff --git a/assets/index.html-DyXM_9kx.js b/assets/index.html-DyXM_9kx.js new file mode 100644 index 000000000..e426b9b21 --- /dev/null +++ b/assets/index.html-DyXM_9kx.js @@ -0,0 +1 @@ +import{_ as u,r as s,o as p,c as g,a as t,d as o,b as n,e as m,w as l}from"./app-CRZRGfEE.js";const f={};function y(b,e){const d=s("tool-tiles"),r=s("os-link"),i=s("RouteLink"),a=s("ClientOnly");return p(),g("div",null,[e[30]||(e[30]=t("br",null,null,-1)),e[31]||(e[31]=t("h1",{id:"downloads",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#downloads"},[t("span",null,"Downloads")])],-1)),e[32]||(e[32]=t("p",null,[o("With "),t("strong",null,"Needle Engine"),o(", you can create fully interactive 3D websites. They can be deployed anywhere on the web and get optimized automatically by the "),t("strong",null,"Needle Engine Build Pipeline"),o(" reducing asset size by up x100 without compromising quality.")],-1)),e[33]||(e[33]=t("p",null,"Needle Engine is available as a package for Unity, add-on for Blender, as a ready-to-go Web Component, and as npm package for projects without an editor integration. Each of these comes with the same components and building blocks โ€“ the choice is yours.",-1)),e[34]||(e[34]=t("h2",{id:"choose-your-workflow",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#choose-your-workflow"},[t("span",null,"Choose your Workflow")])],-1)),n(d),e[35]||(e[35]=m('

    Code Editor and Tools

    Install a code editor

    Needle Engine makes it easy to build web apps. That often, but not always, includes coding with JavaScript/TypeScript or writing HTML and CSS to describe user interfacces. We recommend Visual Studio Code for creating and editing these files. It's a free, open-source code editor that runs on Windows, macOS, and Linux.

    ',5)),n(a,null,{default:l(()=>[n(r,{windows_url:"https://code.visualstudio.com/sha/download?build=stable&os=win32-x64-user",osx_url:"https://code.visualstudio.com/sha/download?build=stable&os=darwin-universal"},{default:l(()=>e[0]||(e[0]=[o("Download Visual Studio Code")])),_:1}),e[7]||(e[7]=t("br",null,null,-1)),e[8]||(e[8]=t("br",null,null,-1)),e[9]||(e[9]=t("h3",{id:"other-useful-tools",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#other-useful-tools"},[t("span",null,"Other useful tools")])],-1)),e[10]||(e[10]=t("div",{class:"hint-container tip"},[t("p",{class:"hint-container-title"},"Tips"),t("p",null,"Needle Engine uses the following tools to create your web app, but you don't need to manually install them when using the Unity or Blender integration. We'll guide you through the installation process after you've installed the Needle integration.")],-1)),e[11]||(e[11]=t("br",null,null,-1)),n(r,{windows_url:"https://nodejs.org/dist/v20.9.0/node-v20.9.0-x64.msi",osx_url:"https://nodejs.org/dist/v20.9.0/node-v20.9.0.pkg"},{default:l(()=>e[1]||(e[1]=[o("Node.js 18 LTS or 20 LTS.")])),_:1}),e[12]||(e[12]=o(" Needle Engine uses Node.js to manage, preview and build the web app that you are creating locally on your computer. It is also used for uploading (deploying) your website to the internet. ")),t("p",null,[e[4]||(e[4]=t("br",null,null,-1)),n(r,{windows_url:"https://fwd.needle.tools/needle-engine/toktx/win",osx_url:"https://fwd.needle.tools/needle-engine/toktx/osx",osx_silicon_url:"https://fwd.needle.tools/needle-engine/toktx/osx-silicon"},{default:l(()=>e[2]||(e[2]=[o("KTX Software โ€“ toktx texture tools.")])),_:1}),e[5]||(e[5]=o(" We use toktx by the Khronos Group to locally optimize and compress your 3D files. Learn more about production builds ")),n(i,{to:"/deployment.html#production-builds"},{default:l(()=>e[3]||(e[3]=[o("in the docs")])),_:1}),e[6]||(e[6]=o("."))]),e[13]||(e[13]=t("br",null,null,-1))]),_:1}),e[36]||(e[36]=t("h2",{id:"next-steps",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#next-steps"},[t("span",null,"Next Steps")])],-1)),e[37]||(e[37]=t("p",null,"Now that you've installed Needle Engine, you're ready to dive deeper into project creation, component workflows, scripting, deployment and more.",-1)),t("ul",null,[e[20]||(e[20]=t("li",null,[t("a",{href:"https://engine.needle.tools/samples",target:"_blank",rel:"noopener noreferrer"},"Needle Engine Samples")],-1)),t("li",null,[n(i,{to:"/export.html"},{default:l(()=>e[14]||(e[14]=[o("Exporting 3D objects and content")])),_:1})]),t("li",null,[n(i,{to:"/project-structure.html"},{default:l(()=>e[15]||(e[15]=[o("Project Structure")])),_:1})]),t("li",null,[n(i,{to:"/deployment.html"},{default:l(()=>e[16]||(e[16]=[o("Deploy your website to the web")])),_:1})]),t("li",null,[n(i,{to:"/getting-started/typescript-essentials.html"},{default:l(()=>e[17]||(e[17]=[o("Typescript Essentials")])),_:1})]),t("li",null,[n(i,{to:"/getting-started/for-unity-developers.html"},{default:l(()=>e[18]||(e[18]=[o("Needle Engine for Unity Developers")])),_:1})]),t("li",null,[n(i,{to:"/scripting.html"},{default:l(()=>e[19]||(e[19]=[o("Scripting Reference")])),_:1})])]),t("p",null,[e[22]||(e[22]=o("In case you need troubleshooting help, please see the ")),n(i,{to:"/faq.html"},{default:l(()=>e[21]||(e[21]=[o("Questions and Answers โ€“ FAQ")])),_:1}),e[23]||(e[23]=o(" section.")),e[24]||(e[24]=t("br",null,null,-1)),e[25]||(e[25]=o(" We welcome you to join our ")),e[26]||(e[26]=t("a",{href:"https://forum.needle.tools",target:"_blank",rel:"noopener noreferrer"},"Forum",-1)),e[27]||(e[27]=o(" and ")),e[28]||(e[28]=t("a",{href:"https://discord.needle.tools",target:"_blank",rel:"noopener noreferrer"},"Discord Community",-1)),e[29]||(e[29]=o("."))])])}const h=u(f,[["render",y],["__file","index.html.vue"]]),x=JSON.parse('{"path":"/getting-started/","title":"Getting Started & Installation","lang":"en-US","frontmatter":{"lang":"en-US","title":"Getting Started & Installation","next":"../project-structure.md","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/getting started & installation.png"}],["meta",{"name":"og:description","content":"---\\nWith Needle Engine, you can create fully interactive 3D websites.\\nThey can be deployed anywhere on the web and get optimized automatically by the Needle Engine Build Pipeline reducing asset size by up x100 without compromising quality.\\nNeedle Engine is available as a package for Unity, add-on for Blender, as a ready-to-go Web Component, and as npm package for projects without an editor integration. Each of these comes with the same components and building blocks โ€“ the choice is yours."}]],"description":"---\\nWith Needle Engine, you can create fully interactive 3D websites.\\nThey can be deployed anywhere on the web and get optimized automatically by the Needle Engine Build Pipeline reducing asset size by up x100 without compromising quality.\\nNeedle Engine is available as a package for Unity, add-on for Blender, as a ready-to-go Web Component, and as npm package for projects without an editor integration. Each of these comes with the same components and building blocks โ€“ the choice is yours."},"headers":[{"level":2,"title":"Choose your Workflow","slug":"choose-your-workflow","link":"#choose-your-workflow","children":[]},{"level":2,"title":"Code Editor and Tools","slug":"code-editor-and-tools","link":"#code-editor-and-tools","children":[{"level":3,"title":"Install a code editor","slug":"install-a-code-editor","link":"#install-a-code-editor","children":[]},{"level":3,"title":"Other useful tools","slug":"other-useful-tools","link":"#other-useful-tools","children":[]}]},{"level":2,"title":"Next Steps","slug":"next-steps","link":"#next-steps","children":[]}],"git":{"updatedTime":1727189596000},"filePathRelative":"getting-started/index.md"}');export{h as comp,x as data}; diff --git a/assets/index.html-Msujlet7.js b/assets/index.html-Msujlet7.js new file mode 100644 index 000000000..2e162fd40 --- /dev/null +++ b/assets/index.html-Msujlet7.js @@ -0,0 +1 @@ +import{_ as n,o,c as a,a as t}from"./app-CRZRGfEE.js";const i={};function s(r,e){return o(),a("div",null,e[0]||(e[0]=[t("h1",{id:"integrate-with-other-tools",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#integrate-with-other-tools"},[t("span",null,"Integrate with other tools")])],-1),t("div",{class:"hint-container warning"},[t("p",{class:"hint-container-title"},"This page is under construction.")],-1)]))}const l=n(i,[["render",s],["__file","index.html.vue"]]),d=JSON.parse('{"path":"/custom-integrations/","title":"Integrate with other tools","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/custom integrations.png"}],["meta",{"name":"og:description","content":":"}]],"description":":"},"headers":[],"git":{"updatedTime":1727182460000},"filePathRelative":"custom-integrations/index.md"}');export{l as comp,d as data}; diff --git a/assets/index.html-_acHVPU1.js b/assets/index.html-_acHVPU1.js new file mode 100644 index 000000000..af7d05e72 --- /dev/null +++ b/assets/index.html-_acHVPU1.js @@ -0,0 +1,73 @@ +import{_ as k,r as l,o as r,c as d,e as h,b as e,w as n,a as i,d as s}from"./app-CRZRGfEE.js";const o="/docs/logo.png",g="/docs/imgs/logo-webcomponents.png",c="/docs/imgs/threejs-logo.webp",y={};function E(C,a){const t=l("CodeGroupItem"),p=l("CodeGroup");return r(),d("div",null,[a[2]||(a[2]=h('
    Needle Logo + Web Components Logo + three.js Logo

    Needle Engine as Web Component

    Needle Engine provides an easy-to-use web component that can be used to display rich, interactive 3D scenes directly in HTML with just a few lines of code. It's the same web component that powers our integrations.

    Once you outgrow the configuration options of the web component, you can extend it with custom scripts and components, and full programmatic scene graph access.

    Use the integrations!

    For complex 3D scenes and fast iteration, we recommend using Needle Engine with one of our integrations. They provide a powerful creation workflow, including a live preview, hot reloading, and an advanced build pipeline with 3D optimizations.

    Quick Start

    ',7)),e(p,null,{default:n(()=>[e(t,{title:"index.html"},{default:n(()=>a[0]||(a[0]=[i("div",{class:"language-html","data-highlighter":"shiki","data-ext":"html","data-title":"html",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[i("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[i("code",null,[i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"<"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE"}},"html"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},">")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"<"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE"}},"head"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},">")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," <"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE"}},"script"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890"}}," type"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"module"'),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890"}}," src"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"https://unpkg.com/@needle-tools/engine/dist/needle-engine.min.js"'),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},">")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," <"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"/"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE"}},"script"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},">")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"<"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE"}},"body"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890"}}," style"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"'),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},'margin:0; padding:0;"'),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},">")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," <"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE"}},"needle-engine"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890"}}," src"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"https://cloud.needle.tools/api/v1/public/873a48a/10801b111/MusicalInstrument.glb"'),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890"}}," background-blurriness"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"0.8"'),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},">")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"")])])])],-1)])),_:1}),e(t,{title:"Result"},{default:n(()=>a[1]||(a[1]=[i("iframe",{src:"/docs/code-samples/basic-webcomponent.html",style:{width:"100%","aspect-ratio":"16/9",outline:"none",border:"none"},allow:"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture; xr-spatial-tracking",allowfullscreen:""},null,-1)])),_:1})]),_:1}),a[3]||(a[3]=h(`

    Open this example on Stackblitz

    Install from npm

    You can work directly with Needle Engine without using any Integration. Needle Engine uses three.js as scene graph and rendering library, so all functionality from three.js is available in Needle as well.

    You can install Needle Engine from npm by running:

    npm i @needle-tools/engine

    Install needle-engine from a CDN

    While our default template uses vite, Needle Engine can also be used directly with vanilla Javascript โ€“ without using any bundler.

    You can add a complete, prebundled version of Needle Engine to your website with just a line of code. This includes our core components, physics, particles, networking, XR, and more. Use this if you're not sure!

    <script type="module" 
    +    src="https://unpkg.com/@needle-tools/engine/dist/needle-engine.min.js">
    +</script>

    If you know your project doesn't require physics features, you can also use a smaller version of Needle Engine, without the physics engine. This will reduce the total downloaded size.

    <script type="module"
    +    src="https://unpkg.com/@needle-tools/engine/dist/needle-engine.light.min.js">
    +</script>

    Many examples can be found on StackBlitz.

    Rapid Prototyping on StackBlitz

    For quick experiments, we provide a convenient link to create a new project ready to start, powered by StackBlitz:
    engine.needle.tools/new

    Rapid Prototyping on Glitch

    Under construction

    Local Development with VS Code

    If you want to work with Needle Engine without any integration, then you'll likely want to run a local server for your website. Here's how you can do that with Visual Studio Code:

    1. Open the folder with your HTML file in Visual Studio Code.
    2. Install the LiveServer extension.
    3. Activate live-server (there's a button "Go Live" in the footer of VSCode)
    4. Open http://localhost:5500/index.html in your web browser, if it doesn't open automatically.

    three.js and Needle Engine

    Since Needle Engine uses three.js as scene graph and rendering library, all functionality from three.js is available in Needle as well and can be used from component scripts. We're using a fork of three.js that includes additional features and improvements, especially in relation to WebXR, Animation, and USDZ export.

    Tips

    Make sure to update the <needle-engine src="myScene.glb"> path to an existing glb file or download this sample glb and put it in the same folder as the index.html, name it myScene.glb or update the src path.

    <!DOCTYPE html>
    +<html lang="en">
    +    
    +<head>
    +    <meta charset="UTF-8" />
    +    <link rel="icon" href="favicon.ico">
    +    <meta name="viewport" content="width=device-width, user-scalable=no">
    +    <title>Made with Needle</title>
    +
    +    <!-- importmap -->
    +    <script type="importmap">
    +        {
    +          "imports": {
    +            "three":  "https://unpkg.com/three/build/three.module.js",
    +            "three/": "https://unpkg.com/three/"
    +          }
    +        }
    +    </script>
    +    <!-- parcel require must currently defined somewhere for peerjs -->
    +    <script> var parcelRequire; </script>
    +    
    +    <!-- the .light version does not include dependencies like Rapier.js (so no physics) to reduce the bundle size, if your project needs physics then just change it to needle-engine.min.js -->
    +    <script type="module" src="https://unpkg.com/@needle-tools/engine@3.5.6-alpha/dist/needle-engine.light.min.js"></script>
    +
    +    <style>
    +        body { margin: 0; }
    +        needle-engine {
    +            position: absolute;
    +            display: block;
    +            width: 100%;
    +            height: 100%;
    +            background: grey;
    +        }
    +    </style>
    +
    +</head>
    +
    +<body>
    +
    +    <!-- load a gltf or glb here as your scene and listen to the finished event to start interacting with it -->
    +    <needle-engine src="myScene.glb" loadfinished="onLoaded"></needle-engine>
    +
    +</body>
    +
    +<script>
    +    function onLoaded(ctx) {
    +        console.log("Loading a glb file finished ๐Ÿ˜Ž");
    +        console.log("This is the scene: ", ctx.scene);
    +    }
    +</script>
    +
    +</html>

    View on github

    `,23))])}const m=k(y,[["render",E],["__file","index.html.vue"]]),B=JSON.parse('{"path":"/three/","title":"Needle Engine as Web Component","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/three.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[{"level":3,"title":"Quick Start","slug":"quick-start","link":"#quick-start","children":[]},{"level":2,"title":"Install from npm","slug":"install-from-npm","link":"#install-from-npm","children":[]},{"level":2,"title":"Install needle-engine from a CDN","slug":"install-needle-engine-from-a-cdn","link":"#install-needle-engine-from-a-cdn","children":[]},{"level":2,"title":"Rapid Prototyping on StackBlitz","slug":"rapid-prototyping-on-stackblitz","link":"#rapid-prototyping-on-stackblitz","children":[]},{"level":2,"title":"Rapid Prototyping on Glitch","slug":"rapid-prototyping-on-glitch","link":"#rapid-prototyping-on-glitch","children":[]},{"level":2,"title":"Local Development with VS Code","slug":"local-development-with-vs-code","link":"#local-development-with-vs-code","children":[]},{"level":2,"title":"three.js and Needle Engine","slug":"three.js-and-needle-engine","link":"#three.js-and-needle-engine","children":[]}],"git":{"updatedTime":1727707190000},"filePathRelative":"three/index.md"}');export{m as comp,B as data}; diff --git a/assets/index.html-gQ6khto9.js b/assets/index.html-gQ6khto9.js new file mode 100644 index 000000000..9bae3b700 --- /dev/null +++ b/assets/index.html-gQ6khto9.js @@ -0,0 +1 @@ +import{_ as c,r as n,o as m,c as h,e as a,b as r,w as i,a as t,d as o}from"./app-CRZRGfEE.js";const u="/docs/imgs/unity-logo.webp",g="/docs/imgs/unity-project-local-template.jpg",f="/docs/imgs/unity-project-remote-template.jpg",y={};function b(w,e){const l=n("needle-button"),s=n("NoDownloadYet"),p=n("video-embed"),d=n("RouteLink");return m(),h("div",null,[e[11]||(e[11]=a('

    Needle Engine for Unity

    Install the Unity Package

    ',4)),r(s,null,{default:i(()=>[e[1]||(e[1]=t("br",null,null,-1)),r(l,{event_goal:"download_unity",event_position:"getting_started",large:"",href:"https://engine.needle.tools/downloads/unity?utm_source=needle_docs&utm_content=getting_started",same_tab:"",next_url:"/docs/unity/"},{default:i(()=>e[0]||(e[0]=[t("strong",null,"Download Needle Engine for Unity",-1)])),_:1})]),_:1}),e[12]||(e[12]=a('
    1. Drop the downloaded .unitypackage file into a Unity project and confirm that you want to import it.

    2. Wait a moment for the installation and import to finish. A window may open stating that "A new scoped registry is now available in the Package Manager.". This is our Needle Package registry. You can safely close that window.

    3. Explore Samples.
      Select the menu option Needle Engine > Explore Samples to view, open and modify all available sample scenes.

    Quickstart Video Tutorial

    ',2)),r(p,{src:"https://www.youtube.com/watch?v=3dB-d1Jo_Mk",limit_height:""}),e[13]||(e[13]=a('

    Start from a Sample

    There are 100+ samples that cover a wide range of topics, use cases, and industries.
    For a quick overview, take a look at our Samples page.

    All of these samples are available directly in Unity:

    1. Go to Needle Engine > Explore Samples to browse for samples
    2. Click "Install Samples" to install the samples package right inside your editor.
    3. Choose any sample and click on Open Scene.

    The Samples are read-only โ€“ that makes them easy to update.

    Our samples scenes are part of a UPM package in Unity. This means that you can't edit the assets and scripts in them directly โ€“ they are read-only. To edit an asset from the samples package, copy it into your project's Assets folder. To edit a script from the samples package, copy it into your web project's src folder.

    Start from a template

    We provide a number of Scene Templates for quickly starting new projects.
    These allow you to go from idea to prototype in a few clicks.

    1. Click on File > New Scene

    2. Select one of the templates with (needle) in their name and click Create.
      We recommend the Collaborative Sandbox template which is a great way to get started with interactivity, multiplayer, and adding assets.

    3. Click Play to install and startup your new web project.

    20220822-140539-wqvW-Unity_oC0z-needle

    Start from scratch

    If you don't want to start from a scene template, you can follow these steps.
    Effectively, we're going to recreate the "Minimal (Needle)" template that's shipping with the package.

    1. Create a new empty scene

    2. Set up your scene for exporting
      Add an empty GameObject, name it "Exporter" and add an ExportInfo component to it.
      In this component you create and quickly access your exported runtime project.
      It also warns you if any of our packages and modules are outdated or not locally installed in your web project.

      Project Name and Scene Name

      By default, the project name matches the name of your scene. If you want to change that, you can pick or enter a Directory Name where you want to create your new web project. The path is relative to your Unity project.

    3. Choose a web project template Now, select a web project template for your project. The default template is based on Vite, a fast web app bundler.

      Unity ExportInfo local templates

    4. Click Play to install and start your new web project

    Define your own templates

    If you find yourself creating many similar projects, you can create your own local or remote templates using the Project View context menu under Create/Needle Engine/Project Template. Templates can either be local on disk (a folder being copied) or remote repositories (a git repository being cloned).

    Project Folders and Files

    ',14)),t("table",null,[e[10]||(e[10]=t("thead",null,[t("tr",null,[t("th",null,"Folder"),t("th")])],-1)),t("tbody",null,[e[6]||(e[6]=t("tr",null,[t("td",null,[t("strong",null,"Unity")]),t("td")],-1)),e[7]||(e[7]=t("tr",null,[t("td",null,[t("code",null,"Assets")]),t("td",null,"This is where project specific/exclusive assets live.")],-1)),e[8]||(e[8]=t("tr",null,[t("td",null,[t("code",null,"Packages")]),t("td",null,[o("This is where packages installed for this project live. A package can contain any asset type. The main difference is that it can be added to multiple Unity projects. It therefor is a great method to share code or assets. To learn more about packages see "),t("a",{href:"https://docs.unity3d.com/Manual/PackagesList.html",target:"_blank",rel:"noopener noreferrer"},"the Unity documentation about packages"),o(".")])],-1)),e[9]||(e[9]=t("tr",null,[t("td",null,[t("strong",null,"Needle Engine Unity Package")]),t("td")],-1)),t("tr",null,[e[5]||(e[5]=t("td",null,[t("code",null,"Core/Runtime/Components")],-1)),t("td",null,[e[3]||(e[3]=o("Contains all Needle Engine built-in components. Learn more about them in the ")),r(d,{to:"/component-reference.html"},{default:i(()=>e[2]||(e[2]=[o("Components Reference")])),_:1}),e[4]||(e[4]=o("."))])])])]),e[14]||(e[14]=a('

    When creating a new web project in Unity, you can choose to create it from a local template (by default we ship a vite based web template).

    You can also reference remote templates by entering a repository URL in the ExportInfo project path (this can be saved with your scene for example). When creating a new web project the repository will be either cloned or downloaded (depending on if you have git installed) and searched for a needle.config.json file. If none can be found in the cloned repository the root directory will be used. Examples of remote template projects can be found on github.com/needle-engine

    Unity ExportInfo local templates

    Temporary Projects

    If you're planning to only add custom files via NpmDefs and not change the project config (e.g. for a quick fullscreen test), you can prefix the project path with Library. The project will be generated in the Unity Project Library and does not need to be added to source control (the Library folder should be excluded from source control). We call these projects temporary projects. They're great for quickly testing out ideas!

    Typescript in Unity

    NPM Definition are npm packages tightly integrated into the Unity Editor which makes it easily possible to share scripts with multiple web- or even Unity projects.

    C# component stubs for typescript files will also be automatically generated for scripts inside npmdef packages.

    Creating and installing a npmdef

    To create a NPM Definition right click in the Unity Project browser and select Create/NPM Definition.
    You can install a NPM Definition package to your runtime project by e.g. selecting your Export Info component and adding it to the dependencies list (internally this will just add the underlying npm package to your package.json).

    image

    Don't forget to install the newly added package by e.g. clicking Install on the ExportInfo component and also restart the server if it is already running

    To edit the code inside a NPM Definition package just double click the asset NPM Definition asset in your project browser and it will open the vscode workspace that comes with each npmdef.

    ',14))])}const j=c(y,[["render",b],["__file","index.html.vue"]]),v=JSON.parse('{"path":"/unity/","title":"Needle Engine for Unity","lang":"en-US","frontmatter":{"title":"Needle Engine for Unity","editLink":true,"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/preview.jpeg"}],["meta",{"name":"og:description","content":"---"}]],"description":"---"},"headers":[{"level":2,"title":"Install the Unity Package","slug":"install-the-unity-package","link":"#install-the-unity-package","children":[]},{"level":2,"title":"Quickstart Video Tutorial","slug":"quickstart-video-tutorial","link":"#quickstart-video-tutorial","children":[]},{"level":2,"title":"Start from a Sample","slug":"start-from-a-sample","link":"#start-from-a-sample","children":[]},{"level":2,"title":"Start from a template","slug":"start-from-a-template","link":"#start-from-a-template","children":[]},{"level":2,"title":"Start from scratch","slug":"start-from-scratch","link":"#start-from-scratch","children":[]},{"level":2,"title":"Project Folders and Files","slug":"project-folders-and-files","link":"#project-folders-and-files","children":[{"level":3,"title":"Temporary Projects","slug":"temporary-projects","link":"#temporary-projects","children":[]}]},{"level":2,"title":"Typescript in Unity","slug":"typescript-in-unity","link":"#typescript-in-unity","children":[]}],"git":{"updatedTime":1727182460000},"filePathRelative":"unity/index.md"}');export{j as comp,v as data}; diff --git a/assets/kipash.html-BN1wH6PC.js b/assets/kipash.html-BN1wH6PC.js new file mode 100644 index 000000000..36170fe5b --- /dev/null +++ b/assets/kipash.html-BN1wH6PC.js @@ -0,0 +1,37 @@ +import{_ as n,r as h,o as r,c as p,b as a,w as l,a as i,d as s}from"./app-CRZRGfEE.js";const d={};function o(C,t){const k=h("contribution-preview"),e=h("contributions-author");return r(),p("div",null,[a(e,{overviewLink:"/docs/community/contributions",name:"kipash",url:"https://github.com/kipash",profileImage:"https://avatars.githubusercontent.com/u/30328735?s=100&u=f28398f4575da1835d1c710d14763c69418cd0fa&v=4",githubUrl:"https://github.com/kipash"},{default:l(()=>[a(k,{title:"Calculate pointer world position",pageUrl:"/docs/community/contributions/kipash/calculate-pointer-world-position"},{default:l(()=>t[0]||(t[0]=[i("p",null,"https://github.com/needle-tools/needle-engine-support/assets/30328735/92404e43-9d45-4ee2-a018-fb00412b6bd5",-1),i("div",{class:"language-ts","data-highlighter":"shiki","data-ext":"ts","data-title":"ts",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[i("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[i("code",null,[i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Behaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," serializable"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," setWorldPosition "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "@needle-tools/engine"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Object3D"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Vector3 "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "three"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," vector1 "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6","--shiki-light-font-weight":"bold","--shiki-dark-font-weight":"bold"}}," new"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Vector3"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," vector2 "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6","--shiki-light-font-weight":"bold","--shiki-dark-font-weight":"bold"}}," new"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Vector3"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"export"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," class"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," PointerFollower"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," extends"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Behaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," @serializable"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"("),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Object3D"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," target"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?:"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Object3D"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," @serializable"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"()")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," offset"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," number"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," ="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 10"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," update"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," void"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," cam "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"context"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"mainCamera"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," input "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"context"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"input"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"!"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"target "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"||"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," !"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"cam)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," return"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," // get relative mouse position, in range -1 to 1")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," mouse "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," input"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"mousePositionRC"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," // get world position of mouse on the near plane")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," vector1"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"set"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(mouse"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"x"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," mouse"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"y"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," -"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"1"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"unproject"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(cam"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"!"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," // caulculate direction from camera to world mouse")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," vector2"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"copy"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(vector1)"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"sub"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(cam"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"position)"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"normalize"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," // offset it to the wanted distance")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," vector1"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"addScaledVector"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(vector2"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"offset)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," // apply the result")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," setWorldPosition"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"target"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," vector1)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}")])])])],-1)])),_:1})]),_:1})])}const y=n(d,[["render",o],["__file","kipash.html.vue"]]),c=JSON.parse('{"path":"/community/contributions/kipash","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/contributions: kipash.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{y as comp,c as data}; diff --git a/assets/krisrok.html-6_QA53zB.js b/assets/krisrok.html-6_QA53zB.js new file mode 100644 index 000000000..36b48dc0f --- /dev/null +++ b/assets/krisrok.html-6_QA53zB.js @@ -0,0 +1,31 @@ +import{_ as k,r as a,o as r,c as o,b as l,w as e,a as i,d as s}from"./app-CRZRGfEE.js";const p={};function d(c,t){const h=a("contribution-preview"),n=a("contributions-author");return r(),o("div",null,[l(n,{overviewLink:"/docs/community/contributions",name:"krisrok",url:"https://github.com/krisrok",profileImage:"https://avatars.githubusercontent.com/u/3404365?s=100&u=7025bf7e83b4a3cd72dc2cae9cec729080ee8970&v=4",githubUrl:"https://github.com/krisrok"},{default:e(()=>[l(h,{title:"Always open in specific browser",pageUrl:"/docs/community/contributions/krisrok/always-open-in-specific-browser"},{default:e(()=>t[0]||(t[0]=[i("p",null,[s('Add this class to your project to always open with Chrome instead of your default browser (Firefox in my case) when you click "Play" or "Start Server". Note: This is an editor class and should either be put into an editor-only assembly or wrapped in '),i("code",null,"#if UNITY_EDITOR"),s(" and "),i("code",null,"#endif"),s(".")],-1),i("div",{class:"language-csharp","data-highlighter":"shiki","data-ext":"csharp","data-title":"csharp",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[i("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[i("code",null,[i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"using"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," System"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"Diagnostics"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"using"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," UnityEditor"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"using"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," UnityEngine"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"using"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Needle"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"Engine"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"["),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"InitializeOnLoad"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"]")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"public"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," static"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," class"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," CustomBrowserOpen")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," static"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," CustomBrowserOpen"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Init"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"();")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," ["),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"RuntimeInitializeOnLoadMethod"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"]")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," static"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," void"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Init"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ActionsBrowser"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"BeforeOpen "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"+="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ActionsBrowser_BeforeOpen"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," static"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," void"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," ActionsBrowser_BeforeOpen"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"("),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"ActionsBrowser"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"OpenBrowserArguments"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," args"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," args"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"PreventDefault "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," true"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," string"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," processArgs "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," args"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Url"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," var"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," psi "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," new"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," ProcessStartInfo")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," FileName "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "chrome.exe"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},",")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Arguments "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," processArgs")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," };")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Process"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"Start"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"("),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"psi"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},");")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}")])])])],-1)])),_:1})]),_:1})])}const g=k(p,[["render",d],["__file","krisrok.html.vue"]]),C=JSON.parse('{"path":"/community/contributions/krisrok","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/contributions: krisrok.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{g as comp,C as data}; diff --git a/assets/ktx-env-variable-DxwKzzNo.js b/assets/ktx-env-variable-DxwKzzNo.js new file mode 100644 index 000000000..c6b04a827 --- /dev/null +++ b/assets/ktx-env-variable-DxwKzzNo.js @@ -0,0 +1 @@ +const s="/docs/imgs/ktx-env-variable.webp";export{s as _}; diff --git a/assets/llllkatjallll.html-CUXH6RfS.js b/assets/llllkatjallll.html-CUXH6RfS.js new file mode 100644 index 000000000..200328373 --- /dev/null +++ b/assets/llllkatjallll.html-CUXH6RfS.js @@ -0,0 +1,59 @@ +import{_ as n,r as k,o as r,c as p,b as l,w as h,a as i,d as s}from"./app-CRZRGfEE.js";const d={};function C(y,t){const a=k("contribution-preview"),e=k("contributions-author");return r(),p("div",null,[l(e,{overviewLink:"/docs/community/contributions",name:"llllkatjallll",url:"https://github.com/llllkatjallll",profileImage:"https://avatars.githubusercontent.com/u/38395689?s=100&u=7ce0fef973c4819c4f07823568d6f6061abfe410&v=4",githubUrl:"https://github.com/llllkatjallll"},{default:h(()=>[l(a,{title:"Custom VR Button, that appears only on headsets and not on mobile phones",pageUrl:"/docs/community/contributions/llllkatjallll/custom-vr-button-that-appears-only-on-headsets-and-not-on-mobile-phones"},{default:h(()=>t[0]||(t[0]=[i("p",null,"I combined two checks - Needle's check to see if it's a mobile device (this way, you can exclude desktops), and then a second check that uses user agent info to see if it's one of the most common mobile systems. Result: the button does not appear on mobile phones, but it is visible on Quest and Pico ๐Ÿ™‚",-1),i("p",null,"P.S: I am using Svelte for 2D UI handling.",-1),i("div",{class:"language-ts","data-highlighter":"shiki","data-ext":"ts","data-title":"ts",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[i("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[i("code",null,[i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," isMobileDevice"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," NeedleXRSession "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "@needle-tools/engine"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"...")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"// check if this is a mobile phone")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"function"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," isMobilePhone"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," return"),i("span",{style:{"--shiki-light":"#EA76CB","--shiki-dark":"#F4B8E4"}}," /"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Mobi"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"|"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Android"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"|"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"iPhone"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"|"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"iPad"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"|"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"iPod"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"|"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"BlackBerry"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"|"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"IEMobile"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"|"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Opera Mini"),i("span",{style:{"--shiki-light":"#EA76CB","--shiki-dark":"#F4B8E4"}},"/"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"i"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"test"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(navigator"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"userAgent)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"...")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"// show the button, if the device is not a mobile phone and VR is supported")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"#"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"if"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," isMobileDevice"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"() "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"&&"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," !"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"isMobilePhone"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"() "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"&&"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," $haveVR "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," <"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"VrButton buttonFunction"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"() => "),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"StartVR"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()}"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," />")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"/"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"if"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}")])])])],-1)])),_:1}),l(a,{title:"Set fallback material for USDZ exporter",pageUrl:"/docs/community/contributions/llllkatjallll/set-fallback-material-for-usdz-exporter"},{default:h(()=>t[1]||(t[1]=[i("p",null,"If you want to set a fallback material for an object that will be exported as USDZ (for AR-mode on iOS), you can add this script to the object, which material should be replaced.",-1),i("p",null,"This is especially useful if you use custom shaders in your scene (they are visible on Desktop+WebXR, but not in AR on iOS).",-1),i("div",{class:"language-ts","data-highlighter":"shiki","data-ext":"ts","data-title":"ts",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[i("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[i("code",null,[i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Behaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," GameObject"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Renderer"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," USDZExporter"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," serializable "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "@needle-tools/engine"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Material"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Object3D "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "three"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"export"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," class"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," FallbackMaterial"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," extends"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Behaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," @serializable"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"("),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Material"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," fallbackMaterial"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"!:"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Material"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," originalMaterial"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?:"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Material"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," usdzExporter"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"!:"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," USDZExporter"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," onEnable"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"usdzExporter "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," GameObject"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"findObjectOfType"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(USDZExporter)"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"!"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"subscribeToBeforeExportEvent"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," onDisable"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"unsubscribeFromBeforeExportEvent"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," subscribeToBeforeExportEvent"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"usdzExporter"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"addEventListener"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"before-export"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"onBeforeExport)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"usdzExporter"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"addEventListener"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"after-export"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"onAfterExport)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," unsubscribeFromBeforeExportEvent"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"usdzExporter"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"removeEventListener"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"before-export"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"onBeforeExport)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"usdzExporter"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"removeEventListener"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"after-export"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"onAfterExport)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," onBeforeExport"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," ="),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," ()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," =>"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," console"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"log"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"onBeforeExport"'),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," renderer "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"gameObject"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"getComponent"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(Renderer)"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"!"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"originalMaterial "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," renderer"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"sharedMaterial"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," renderer"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"sharedMaterial "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"fallbackMaterial"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," onAfterExport"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," ="),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," ()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," =>"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," console"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"log"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"onAfterExport"'),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," renderer "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"gameObject"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"getComponent"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(Renderer)"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"!"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," renderer"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"sharedMaterial "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"originalMaterial"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}")])])])],-1)])),_:1})]),_:1})])}const o=n(d,[["render",C],["__file","llllkatjallll.html.vue"]]),F=JSON.parse('{"path":"/community/contributions/llllkatjallll","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/contributions: llllkatjallll.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{o as comp,F as data}; diff --git a/assets/marwie.html-DsbxB-fW.js b/assets/marwie.html-DsbxB-fW.js new file mode 100644 index 000000000..244bd6d33 --- /dev/null +++ b/assets/marwie.html-DsbxB-fW.js @@ -0,0 +1,144 @@ +import{_ as n,r as a,o as r,c as d,b as h,w as l,a as i,d as s}from"./app-CRZRGfEE.js";const p={};function C(y,t){const k=a("contribution-preview"),e=a("contributions-author");return r(),d("div",null,[h(e,{overviewLink:"/docs/community/contributions",name:"marwie",url:"https://github.com/marwie",profileImage:"https://avatars.githubusercontent.com/u/5083203?s=100&v=4",githubUrl:"https://github.com/marwie"},{default:l(()=>[h(k,{title:"Camera Video Background",pageUrl:"/docs/community/contributions/marwie/camera-video-background"},{default:l(()=>t[0]||(t[0]=[i("p",null,[s("Put it anywhere in your scene to render a camera video behind your 3D scene "),i("a",{href:"https://linen-upbeat-sailboat.glitch.me/",target:"_blank",rel:"noopener noreferrer"},"Live demo")],-1),i("div",{class:"language-ts","data-highlighter":"shiki","data-ext":"ts","data-title":"ts",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[i("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[i("code",null,[i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Behaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ClearFlags"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," RGBAColor "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "@needle-tools/engine"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"export"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," class"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," VideoBackground"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," extends"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Behaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," async"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," awake"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," // create video element and put it inside the component")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," video "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," document"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"createElement"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"video"'),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," video"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"style"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"cssText "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}}," `")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}}," position: fixed;")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}}," min-width: 100%;")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}}," min-height: 100%;")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}}," z-index: -1;")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}}," `")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"context"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"domElement"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"shadowRoot"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"!."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"appendChild"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(video)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," // get webcam input")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," input "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," await"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," navigator"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"mediaDevices"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"getUserMedia"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," video"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," true"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ("),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"!"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"input) "),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"return"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," video"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"srcObject "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," input"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," video"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"play"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," // make sure the camera background is transparent")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," camera "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"context"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"mainCameraComponent"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," (camera) "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," camera"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"clearFlags "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ClearFlags"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"SolidColor"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," camera"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"backgroundColor "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6","--shiki-light-font-weight":"bold","--shiki-dark-font-weight":"bold"}}," new"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," RGBAColor"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"125"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 125"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 125"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 0"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}")])])])],-1)])),_:1}),h(k,{title:"USDZ: Hide Object on Start",pageUrl:"/docs/community/contributions/marwie/usdz-hide-object-on-start"},{default:l(()=>t[1]||(t[1]=[i("p",null,[s("This is an example from our "),i("em",null,"Everywhere Actions"),s(". The following script hides an object on start on Android and on iOS AR")],-1),i("div",{class:"language-ts","data-highlighter":"shiki","data-ext":"ts","data-title":"ts",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[i("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[i("code",null,[i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"export"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," class"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," HideOnStart"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," extends"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Behaviour"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," implements"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," UsdzBehaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," start"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"gameObject"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"visible "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," false"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," createBehaviours"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"("),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"ext"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," model"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," _context"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," (model"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"uuid "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"==="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"gameObject"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"uuid)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ext"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"addBehavior"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6","--shiki-light-font-weight":"bold","--shiki-dark-font-weight":"bold"}},"new"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," BehaviorModel"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"HideOnStart_"'),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," +"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"gameObject"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"name"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},",")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," TriggerBuilder"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"sceneStartTrigger"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},",")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ActionBuilder"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"fadeAction"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(model"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 0"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," false"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ))"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," beforeCreateDocument"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"gameObject"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"visible "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," true"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," afterCreateDocument"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"gameObject"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"visible "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," false"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}")])])])],-1)])),_:1}),h(k,{title:"Everywhere Action: Emphasize on Click",pageUrl:"/docs/community/contributions/marwie/everywhere-action-emphasize-on-click"},{default:l(()=>t[2]||(t[2]=[i("p",null,"Example for adding custom USDZ behaviours for iOS AR",-1),i("p",null,"This is an USDZ / iOS AR only example",-1),i("div",{class:"language-ts","data-highlighter":"shiki","data-ext":"ts","data-title":"ts",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[i("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[i("code",null,[i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"export"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," class"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," EmphasizeOnClick"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," extends"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Behaviour"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," implements"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," UsdzBehaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," @serializable"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"()")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," target"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?:"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Object3D"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," @serializable"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"()")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," duration"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," number"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," ="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 0.5"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," @serializable"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"()")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," motionType"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," MotionType "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," MotionType"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"bounce"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," beforeCreateDocument"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," createBehaviours"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"("),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"ext"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," model"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," _context"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ("),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"!"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"target) "),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"return"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," (model"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"uuid "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"==="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"gameObject"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"uuid) "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," emphasize "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6","--shiki-light-font-weight":"bold","--shiki-dark-font-weight":"bold"}}," new"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," BehaviorModel"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"emphasize "'),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," +"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"name"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},",")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," TriggerBuilder"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"tapTrigger"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"gameObject)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},",")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ActionBuilder"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"emphasize"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"target"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"duration"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"motionType"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," undefined"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "basic"'),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},",")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," )"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ext"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"addBehavior"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(emphasize)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," afterCreateDocument"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"("),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"_ext"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," _context"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}")])])])],-1)])),_:1}),h(k,{title:"Control a Timeline by scroll",pageUrl:"/docs/community/contributions/marwie/control-a-timeline-by-scroll"},{default:l(()=>t[3]||(t[3]=[i("p",null,"Use the mouse wheel or touch delta to update a timeline's time.",-1),i("div",{class:"language-ts","data-highlighter":"shiki","data-ext":"ts","data-title":"ts",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[i("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[i("code",null,[i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Behaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," PlayableDirector"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," serializeable "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "@needle-tools/engine"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Mathf "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "@needle-tools/engine"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"// Example of setting a timeline's time ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"// without relying on any HTML elements.")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"// Here we directly use the mousewheel scroll and the touch delta")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"export"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," class"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," ScrollTimeline_2"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," extends"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Behaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," @serializeable"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"("),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"PlayableDirector"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," timeline"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?:"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," PlayableDirector"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," @serializeable"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"()")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," scrollSpeed"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," number"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," ="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 0.5"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," @serializeable"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"()")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," lerpSpeed"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," number"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," ="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 2.5"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," targetTime"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," number"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," ="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 0"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," start"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"timeline"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"pause"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," // Grab the mousewheel event")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," window"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"addEventListener"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"wheel"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," ("),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"evt"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," WheelEvent"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},")"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," =>"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"updateTime"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(evt"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"deltaY))"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," // Touch events are a bit more complicated")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," // We need to keep track of the last touch position")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," // and calculate the delta between the current and the last position")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," let"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," lastTouchPosition "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," -"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"1"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," window"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"addEventListener"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"touchmove"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," ("),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"evt"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," TouchEvent"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},")"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," =>"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," delta "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," evt"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"touches["),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"]"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"clientY "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"-"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," lastTouchPosition"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," // We only want to apply the delta if it's not TOO big")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," // e.g. when the user is scrolling the page")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," (delta "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"<"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 10"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},") "),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"updateTime"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"-"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"delta)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," // Update the last touch position")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," lastTouchPosition "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," evt"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"touches["),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"]"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"clientY"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," updateTime"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"("),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"delta"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ("),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"!"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"timeline) "),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"return"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"targetTime "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"+="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," delta "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"*"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 0.01"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," *"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"scrollSpeed"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"targetTime "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Mathf"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"clamp"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"targetTime"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 0"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"timeline"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"duration)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," onBeforeRender"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," void"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ("),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"!"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"timeline) "),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"return"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"timeline"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"pause"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"timeline"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"time "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Mathf"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"lerp"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"timeline"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"time"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"targetTime"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"lerpSpeed "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"*"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"context"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"time"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"deltaTime)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"timeline"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"evaluate"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}")])])])],-1)])),_:1}),h(k,{title:"Code Contribution Example",pageUrl:"/docs/community/contributions/marwie/code-contribution-example"},{default:l(()=>t[4]||(t[4]=[i("p",null,"This is mostly a basic example on how to contribute. It will then be added on our documentation contributions page: https://engine.needle.tools/docs/community/contributions",-1),i("p",null,"Please include at least one code snippet, for example like this:",-1),i("div",{class:"language-ts","data-highlighter":"shiki","data-ext":"ts","data-title":"ts",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[i("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[i("code",null,[i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Behaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," serializable "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "@needle-tools/engine"')]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Object3D "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "three"')]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"export"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," class"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," MyComponent"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," extends"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Behaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," @serializable"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"("),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Object3D"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," myObjectReference"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?:"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Object3D"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," start"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," console"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"log"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"Hello world"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," update"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," // called every frame")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}")])])])],-1)])),_:1})]),_:1})])}const F=n(p,[["render",C],["__file","marwie.html.vue"]]),E=JSON.parse('{"path":"/community/contributions/marwie","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/contributions: marwie.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{F as comp,E as data}; diff --git a/assets/meta-test.html-Bv0TrQjv.js b/assets/meta-test.html-Bv0TrQjv.js new file mode 100644 index 000000000..675df420d --- /dev/null +++ b/assets/meta-test.html-Bv0TrQjv.js @@ -0,0 +1 @@ +import{_ as o,r as n,o as r,c as a,a as s,d as i,b as h,e as d}from"./app-CRZRGfEE.js";const m={};function u(l,e){const t=n("metalink");return r(),a("div",null,[s("p",null,[e[0]||(e[0]=i("Hello world ")),h(t)]),e[1]||(e[1]=d('
    meta:

    my_test_header

    Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sy but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which loo but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which loo There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looIt uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which loo but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which loo but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which loo but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which loo but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which loo but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which loo

    There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage

    UI Canvas

    of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which loo There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which loo There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which loo There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which loo There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which loo

    How physics works

    but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which loo

    ',8))])}const c=o(m,[["render",u],["__file","meta-test.html.vue"]]),g=JSON.parse('{"path":"/meta-test.html","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/meta test.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[{"level":3,"title":"my_test_header","slug":"my-test-header","link":"#my-test-header","children":[]},{"level":3,"title":"UI Canvas","slug":"ui-canvas","link":"#ui-canvas","children":[]},{"level":3,"title":"How physics works","slug":"how-physics-works","link":"#how-physics-works","children":[]}],"git":{"updatedTime":1671370582000},"filePathRelative":"_meta-test.md"}');export{c as comp,g as data}; diff --git a/assets/metalink-RADuWAM2.js b/assets/metalink-RADuWAM2.js new file mode 100644 index 000000000..f697d3cc0 --- /dev/null +++ b/assets/metalink-RADuWAM2.js @@ -0,0 +1 @@ +import{_}from"./app-CRZRGfEE.js";const n={__name:"metalink",setup(r,{expose:t}){t();const e={};return Object.defineProperty(e,"__isScriptSetup",{enumerable:!1,value:!0}),e}};function s(r,t,e,o,a,p){return" ``` hello ``` "}const u=_(n,[["render",s],["__file","metalink.vue"]]);export{u as default}; diff --git a/assets/microphone-access-in-a-browser-window-and-streamed-playback.html-DC969LS3.js b/assets/microphone-access-in-a-browser-window-and-streamed-playback.html-DC969LS3.js new file mode 100644 index 000000000..54e27034d --- /dev/null +++ b/assets/microphone-access-in-a-browser-window-and-streamed-playback.html-DC969LS3.js @@ -0,0 +1,65 @@ +import{_ as n,r as h,o as t,c as k,a as i,b as l,e as p}from"./app-CRZRGfEE.js";const e={};function r(d,s){const a=h("contribution-header");return t(),k("div",null,[s[0]||(s[0]=i("p",null,[i("a",{href:"/docs/community/contributions"},"Overview")],-1)),l(a,{url:"https://github.com/ROBYER1",author:"ROBYER1",page:"/docs/community/contributions/robyer1",profileImage:"https://avatars.githubusercontent.com/u/10745594?s=100&u=daf2c8b5dad729e556ae2a01c721672b24bc108a&v=4",githubUrl:"https://github.com/needle-tools/needle-engine-support/discussions/192",title:"Microphone access in a browser window (and streamed playback)",gradient:"True"}),s[1]||(s[1]=p(`

    A simple script to show how to request access to, then access a microphone device and also play back the audio stream to debug it. A useful starting point for making an experience revolving around microphone access.

    import { Behaviour } from "@needle-tools/engine";
    +
    +export class Microphone extends Behaviour {
    +  start() {
    +    this.getLocalStream();
    +  }
    +
    +  public el: Element;
    +
    +  attachStream(stream, el, options) {
    +    var item;
    +    var URL = window.URL;
    +    var element = el;
    +    var opts = {
    +      autoplay: true,
    +      mirror: false,
    +      muted: false,
    +      audio: false,
    +      disableContextMenu: false,
    +    };
    +
    +    if (options) {
    +      for (item in options) {
    +        opts[item] = options[item];
    +      }
    +    }
    +
    +    if (!element) {
    +      element = document.createElement(opts.audio ? "audio" : "video");
    +    } else if (element.tagName.toLowerCase() === "audio") {
    +      opts.audio = true;
    +    }
    +
    +    if (opts.autoplay) element.autoplay = "autoplay";
    +    if (opts.muted) element.muted = true;
    +    if (!opts.audio && opts.mirror) {
    +      ["", "moz", "webkit", "o", "ms"].forEach(function (prefix) {
    +        var styleName = prefix ? prefix + "Transform" : "transform";
    +        element.style[styleName] = "scaleX(-1)";
    +      });
    +    }
    +
    +    element.srcObject = stream;
    +    return element;
    +  }
    +
    +  getLocalStream() {
    +    navigator.mediaDevices
    +      .getUserMedia({
    +        video: false,
    +        audio: true,
    +      })
    +      .then((stream) => {
    +        var doesnotexist = !this.el;
    +        this.el = this.attachStream(stream, this.el, {
    +          audio: true,
    +          autoplay: true,
    +        });
    +        if (doesnotexist) document.body.appendChild(this.el);
    +      })
    +      .catch((err) => {
    +        console.log("u got an error:" + err);
    +      });
    +  }
    +}
    `,2))])}const y=n(e,[["render",r],["__file","microphone-access-in-a-browser-window-and-streamed-playback.html.vue"]]),g=JSON.parse('{"path":"/community/contributions/robyer1/microphone-access-in-a-browser-window-and-streamed-playback","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/robyer1: microphone access in a browser window and streamed playback.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{y as comp,g as data}; diff --git a/assets/modules.html-1xnFAmG8.js b/assets/modules.html-1xnFAmG8.js new file mode 100644 index 000000000..448f8027e --- /dev/null +++ b/assets/modules.html-1xnFAmG8.js @@ -0,0 +1 @@ +import{_ as a,r as i,o as s,c as r,a as t,d as o,b as l,w as p,e as c}from"./app-CRZRGfEE.js";const d={};function u(m,e){const n=i("RouteLink");return s(),r("div",null,[t("p",null,[e[1]||(e[1]=o("Projects can be composed of re-usable pieces that we call ")),l(n,{to:"/project-structure.html#npm-definition-files"},{default:p(()=>e[0]||(e[0]=[t("strong",null,"NpmDef",-1)])),_:1}),e[2]||(e[2]=o(" (which stands for Npm Defintion File)."))]),e[3]||(e[3]=c('

    Below you can find links to other repositories that contain Unity packages. These packages can be installed like any Unity package and used in your own projects. They usually contain eihter examples or modules that we use ourselves, but that are not ready to be part of the core Needle Engine.

    • Custom Timeline Tracks
      Video Track (sync video playback to a Timeline) CssTrack (control css properties from the Timeline)

    • Splines (for Unity 2022.1+)
      Export splines to three.js SplineWalker for controlling camera motion based on a spline Timeline track to control SplineWalker

    • Google Drive Integration
      Sketches around drag-drop integration of Google Drive, file picking, app integration

    Github repository

    ',3))])}const g=a(d,[["render",u],["__file","modules.html.vue"]]),f=JSON.parse('{"path":"/modules.html","title":"Additional Modules","lang":"en-US","frontmatter":{"title":"Additional Modules","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/additional modules.png"}],["meta",{"name":"og:description","content":"---\\nProjects can be composed of re-usable pieces that we call NpmDef (which stands for Npm Defintion File).\\nBelow you can find links to other repositories that contain Unity packages. These packages can be installed like any Unity package and used in your own projects. They usually contain eihter examples or modules that we use ourselves, but that are not ready to be part of the core Needle Engine."}]],"description":"---\\nProjects can be composed of re-usable pieces that we call NpmDef (which stands for Npm Defintion File).\\nBelow you can find links to other repositories that contain Unity packages. These packages can be installed like any Unity package and used in your own projects. They usually contain eihter examples or modules that we use ourselves, but that are not ready to be part of the core Needle Engine."},"headers":[],"git":{"updatedTime":1725399379000},"filePathRelative":"modules.md"}');export{g as comp,f as data}; diff --git a/assets/needle-button-CkzDHAYk.js b/assets/needle-button-CkzDHAYk.js new file mode 100644 index 000000000..3d475bd61 --- /dev/null +++ b/assets/needle-button-CkzDHAYk.js @@ -0,0 +1 @@ +import{_ as l,o as _,c as u,a as d,f as c,g as f,n as o,u as h}from"./app-CRZRGfEE.js";const a={props:{href:String,secondary:Boolean,same_tab:Boolean,large:Boolean,event_goal:String,event_position:String,next_url:String||void 0},methods:{get_next_url:g}};function g(){if(typeof window>"u")return this.href;if(!this.next_url)return this.href;let e=window.location.origin+window.location.pathname,n=new URL(this.href);return this.next_url&&(console.log(this.next_url,e),e=new URL(this.next_url,e).href,e=encodeURIComponent(e),e+="?t="+Date.now(),n=new URL(n),n.searchParams.append("next",e),n.searchParams.append("t",Date.now().toString())),n.href}const s=()=>{h(e=>({"5058ae9e":e.secondary?"#aaa":"#826bed",b1e81df0:e.large?"1em":".8em","03a7f81f":e.secondary?"#bbb":"#6248be"}))},r=a.setup;a.setup=r?(e,n)=>(s(),r(e,n)):s;const m=["href","target"];function b(e,n,t,v,p,i){return _(),u("a",{href:i.get_next_url(),target:t.same_tab?"_self":"_blank",class:o(["no-external-link-icon",t.event_goal?"plausible-event-name="+t.event_goal+(t.event_position?" plausible-event-position="+t.event_position:""):""])},[d("button",{class:o(t.event_goal?"plausible-event-name="+t.event_goal+(t.event_position?" plausible-event-position="+t.event_position:""):"")},[c(e.$slots,"default",{},void 0,!0),f("",!0)],2)],10,m)}const x=l(a,[["render",b],["__scopeId","data-v-9b3341da"],["__file","needle-button.vue"]]);export{x as default}; diff --git a/assets/needle-config-json.html-CGJ-KXV-.js b/assets/needle-config-json.html-CGJ-KXV-.js new file mode 100644 index 000000000..3e56519e6 --- /dev/null +++ b/assets/needle-config-json.html-CGJ-KXV-.js @@ -0,0 +1,22 @@ +import{_ as e,r as a,o as n,c as h,e as l,a as i,b as p,w as r,d as k}from"./app-CRZRGfEE.js";const d={};function o(c,s){const t=a("RouteLink");return n(),h("div",null,[s[1]||(s[1]=l(`

    The needle.config.json is used to provide configuration for the Needle Editor integrations and for the Needle Engine build pipeline plugins.

    Paths
    buildDirectoryThis is where the built project files are being copied to
    assetsDirectoryThis is where the Editor integration assets will be copied to or created at (e.g. the .glb files exported from Unity or Blender)
    scriptsDirectoryThis is the directory the Editor integration is watching for code changes to re-generate components
    codegenDirectoryThis is where the Editor integration is outputting generated files to.
    baseUrlRequired for e.g. next.js or SvelteKit integration. When baseUrl is set, relative paths for codegen and inside files are using baseUrl, not assetsDirectory. This is useful in cases where the assetDirectory does not match the server url.
    For example, the path on disk could be "assetsDirectory": "public/assets", but the framework serves files from "baseUrl": "assets".
    Tools
    build : { copy: ["myFileOrDirectory"] }Array of string paths for copying additional files or folders to the buildDirectory. These can either be absolute or relative.

    Basic Example

    {
    +  "buildDirectory": "dist",
    +  "assetsDirectory": "assets",
    +  "scriptsDirectory": "src/scripts",
    +  "codegenDirectory": "src/generated"
    +}

    Copy Example

    {
    +  "buildDirectory": "dist",
    +  "assetsDirectory": "assets",
    +  "scriptsDirectory": "src/scripts",
    +  "codegenDirectory": "src/generated",
    +  "build": {
    +    "copy": [
    +      "cards"
    +    ]
    +  }
    +}

    Example with different baseUrl (e.g. SvelteKit, Next.js)

    Files are exported to static/assets but the framework serves them from /assets. In this case, the baseUrl needs to be set to assets so that relative paths in files are correct.

    {
    +  "baseUrl": "assets",
    +  "buildDirectory": "dist",
    +  "assetsDirectory": "static/assets",
    +  "scriptsDirectory": "src/scripts",
    +  "codegenDirectory": "src/generated"
    +}
    `,10)),i("ul",null,[i("li",null,[p(t,{to:"/project-structure.html"},{default:r(()=>s[0]||(s[0]=[k("Project Structure")])),_:1})])])])}const B=e(d,[["render",o],["__file","needle-config-json.html.vue"]]),C=JSON.parse('{"path":"/reference/needle-config-json.html","title":"needle.config.json","lang":"en-US","frontmatter":{"title":"needle.config.json","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/needle.png"}],["meta",{"name":"og:description","content":"---\\nThe needle.config.json is used to provide configuration for the Needle Editor integrations and for the Needle Engine build pipeline plugins."}]],"description":"---\\nThe needle.config.json is used to provide configuration for the Needle Editor integrations and for the Needle Engine build pipeline plugins."},"headers":[],"git":{"updatedTime":1725399379000},"filePathRelative":"reference/needle-config-json.md"}');export{B as comp,C as data}; diff --git a/assets/needle-engine-attributes.html-Dizdapts.js b/assets/needle-engine-attributes.html-Dizdapts.js new file mode 100644 index 000000000..d32bd8dd5 --- /dev/null +++ b/assets/needle-engine-attributes.html-Dizdapts.js @@ -0,0 +1,16 @@ +import{_ as e}from"./custom-loading-style-s1K1my2z.js";import{_ as i,o as s,c as a,e as n}from"./app-CRZRGfEE.js";const d={};function o(l,t){return s(),a("div",null,t[0]||(t[0]=[n(`

    The <needle-engine> web-component comes with a nice collection of built-in attributes that can be used to modify the look and feel of the loaded scene without the need to add or edit the three.js scene directly.
    The table below shows a list of the most important ones:

    AttributeDescription
    Loading
    srcPath to one or multiple glTF or glb files.
    Supported types are string, string[] or a stringified array (, separated)
    dracoDecoderPathURL to the draco decoder
    dracoDecoderTypedraco decoder type. Options are wasm or js. See three.js documentation
    ktx2DecoderPathURL to the KTX2 decoder
    Rendering
    background-coloroptional, hex color to be used as a background color. Examples: rgb(255, 200, 100), #dddd00
    background-imageoptional, URL to a skybox image (background image) or a preset string: studio, blurred-skybox, quicklook, quicklook-ar
    background-blurrinessoptional, bluriness value between 0 (no blur) and 1 (max blur) for the background-image. Example: background-blurriness="0.5"
    environment-imageoptional, URL to a environment image (environment light) or a preset string: studio, blurred-skybox, quicklook, quicklook-ar
    contactshadowsoptional, render contact shadows
    tone-mappingoptional, supported values are none, linear, neutral, agx
    tone-mapping-exposureoptional number e.g. increase exposure with tone-mapping-exposure="1.5", requires tone-mapping to be set
    Interaction
    autoplayadd or set to true to auto play animations e.g. <needle-engine autoplay
    camera-controlsadd or set to true to automatically add OrbitControls if no camera controls are found in the scene
    auto-rotateadd to enable auto-rotate (only used with camera-controls)
    Events
    loadstartName of the function to call when loading starts. Note that the arguments are (ctx:Context, evt:Event). You can call evt.preventDefault() to hide the default loading overlay
    progressName of the function to call when loading updates. onProgress(ctx:Context, evt: {detail: {context:Context, name:string, index:number, count:number, totalProgress01:number}) { ... }
    loadfinishedName of the function to call when loading finishes
    Loading DisplayAvailable options to change how the Needle Engine loading display looks. Use ?debugloadingrendering for easier editing
    loading-styleOptions are light or dark
    loading-background-colorPRO โ€” Change the loading background color (e.g. =#dd5500)
    loading-text-colorPRO โ€” Change the loading text color
    loading-logo-srcPRO โ€” Change the loading logo image
    primary-colorPRO โ€” Change the primary loading color
    secondary-colorPRO โ€” Change the secondary loading color
    hide-loading-overlayPRO โ€” Do not show the loading overlay, added in Needle Engine > 3.17.1
    Internal
    hashUsed internally, is appended to the files being loaded to force an update (e.g. when the browser has cached a glb file). Should not be edited manually.

    Examples

    <!-- Setting the path to a custom glb to be loaded -->
    +<needle-engine src="path/to/your.glb"></needle-engine>
    <!-- Overriding where the draco decoder is located -->
    +<needle-engine src="path/to/your.glb" dracoDecoderPath="path/to/draco/folder"></needle-engine>

    Setting environment images, playing animation and automatic camera controls. See it live on stackblitz

    <needle-engine
    +      camera-controls
    +      auto-rotate
    +      autoplay
    +      skybox-image="https://dl.polyhaven.org/file/ph-assets/HDRIs/hdr/1k/industrial_sunset_puresky_1k.hdr"
    +      environment-image="https://dl.polyhaven.org/file/ph-assets/HDRIs/hdr/1k/industrial_sunset_puresky_1k.hdr"
    +      src="https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/DamagedHelmet/glTF-Embedded/DamagedHelmet.gltf"
    +      >
    +      </needle-engine>

    Receiving an event when the needle-engine context has finished loading:

    <needle-engine loadfinished="onLoadFinished"> </needle-engine>
    +<script>
    +    function onLoadFinished() {
    +        console.log("Needle Engine has finished loading");
    +    }
    +</script>

    Custom Loading Style (PRO)

    You can easily modify how Needle Engine looks by setting the appropriate attributes on the <needle-engine> web component. Please see the table above for details.

    custom loading
    See code on github

    ',12)]))}const c=i(d,[["render",o],["__file","needle-engine-attributes.html.vue"]]),p=JSON.parse('{"path":"/reference/needle-engine-attributes.html","title":" Configuration","lang":"en-US","frontmatter":{"title":" Configuration","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/ configuration.png"}],["meta",{"name":"og:description","content":"---\\nThe"}]],"description":"---\\nThe"},"headers":[{"level":3,"title":"Custom Loading Style (PRO)","slug":"custom-loading-style-pro","link":"#custom-loading-style-pro","children":[]}],"git":{"updatedTime":1727172155000},"filePathRelative":"reference/needle-engine-attributes.md"}');export{c as comp,p as data}; diff --git a/assets/network-instantiation-of-multiple-objects.html-BiATyjwH.js b/assets/network-instantiation-of-multiple-objects.html-BiATyjwH.js new file mode 100644 index 000000000..4e294cdd0 --- /dev/null +++ b/assets/network-instantiation-of-multiple-objects.html-BiATyjwH.js @@ -0,0 +1,160 @@ +import{_ as t,r as n,o as h,c as k,a as i,b as l,e as p}from"./app-CRZRGfEE.js";const e={};function r(d,s){const a=n("contribution-header");return h(),k("div",null,[s[0]||(s[0]=i("p",null,[i("a",{href:"/docs/community/contributions"},"Overview")],-1)),l(a,{url:"https://github.com/Web3Kev",author:"Web3Kev",page:"/docs/community/contributions/web3kev",profileImage:"https://avatars.githubusercontent.com/u/106066970?s=100&v=4",githubUrl:"https://github.com/needle-tools/needle-engine-support/discussions/153",title:"Network instantiation of multiple objects",gradient:"True"}),s[1]||(s[1]=p(`

    In a multiuser session, typically objects are instantiated using instantiateSynced as such:

    import { Behaviour,GameObject,serializable,InstantiateOptions} from "@needle-tools/engine";
    +import { Vector3, Object3D, } from "three";
    +
    +export class InstantiateObjectForAll extends Behaviour
    +{
    +    @serializable(Object3D)
    +    myPrefab?: GameObject;
    +
    +    public makeObject():void{
    +         const options = new InstantiateOptions();
    +         options.context = this.context;
    +         options.position = new Vector3(0,0,0);
    +         GameObject.instantiateSynced(this.myPrefab, options) as GameObject;
    +    }
    +}

    My particular use-case was for generating programmatically a random scene made of cubes, and that scene had to be the same for all users of the same room. I had used the example above but for some unknown reasons sometimes the scenes were partially rendered when instantiating simultaneously >400 objects. @Marcel of Needle suggested to generate a seed (position of all objects in the scene) and send that seed instead using :

    this.context.connection.send()

    All users using :

    this.context.connection.beginListen()

    would receive any seed previously sent, upon joining the same room, allowing them to instantiate cubes according to that seed (array of Vector3).

    Here is a script illustrating the use of the send method and the beginListen counterpart:

    
    +//This is an example of sending the seed of a randomly generated scene made of cubes, for all other instances logging into the same room to create the same scene.
    +
    +//This script requires a prefab (e.g. a 1x1x1 Cube)
    +//This script will generate and build randomly positioned cubes (random walk) as a child of the object it is attached to. 
    +//The generateSeed() method is in this script called via a button. The button is deactivated once the seed has been transmitted.
    +//Any users joining the same room will receive the seed and build the exact same scene
    +
    +
    +import { Behaviour,GameObject,serializable,InstantiateOptions} from "@needle-tools/engine";
    +import { Vector3, Object3D } from "three";
    +
    +
    +export class NetworkedSeed extends Behaviour
    +{
    +    @serializable(Object3D)
    +    prefab?: GameObject;
    +
    +    @serializable(Object3D)
    +    generateButton?: Object3D;
    +
    +    public seedSize: number = 30; 
    +   
    +    seed: Vector3[] = [];
    +
    +    onEnable(): void {
    +        this.context.connection.beginListen("mySeed", this.onDataReceived);
    +        if(this.generateButton)
    +        {
    +            this.generateButton.visible=true;
    +        }
    +    }
    +    onDisable(): void {
    +        this.context.connection.stopListen("mySeed", this.onDataReceived);
    +    }
    +
    +    onDataReceived = (data: any) => {
    +
    +        console.log("Received data:", data.mySeed);
    +        if(this.seed.length===0)
    +        {
    +            //prevent other generations of the seed
    +            if(this.generateButton)
    +            {
    +                this.generateButton.visible=false;
    +            }
    +
    +            this.seed=data.mySeed;
    +            //build scene
    +            this.buildScene();
    +        }
    +    };
    +
    +
    +    //generate and send seed to all from the button generateButton
    +    public generateSeed():void{
    +
    +        if(this.seed.length==0) //no seed found => generate one
    +        {
    +            this.seed = [];
    +            const uniquePositions = new Set<string>();
    +            
    +            //start at origin
    +            const startPosition = new Vector3(0, 0, 0);
    +            this.seed.push(startPosition.clone());
    +            uniquePositions.add(startPosition.toArray().toString());
    +            
    +            //go for a random walk of length : seedSize
    +            while (this.seed.length < this.seedSize) {
    +                const lastPosition = this.seed[this.seed.length - 1];
    +                let newPosition: Vector3;
    +                
    +                //walk and add position, making sure they are unique
    +                do {
    +                const direction = this.getRandomDirection();
    +                newPosition = lastPosition.clone().add(direction);
    +                } while (uniquePositions.has(newPosition.toArray().toString()));
    +                
    +                this.seed.push(newPosition.clone());
    +                uniquePositions.add(newPosition.toArray().toString());
    +            }
    +            
    +            //send the seed to all on the server
    +            this.sendSeed();
    +
    +            //prevent other generations of the seed
    +            if(this.generateButton)
    +            {
    +                this.generateButton.visible=false;
    +            }
    +        }
    +        
    +        //build scene locally
    +        this.buildScene();
    +    }
    +
    +    private sendSeed():void{
    +        if(this.seed.length!=0)
    +        {
    +            this.context.connection.send("mySeed",{guid:this.guid, mySeed: this.seed});
    +            console.log("------ SEED SENT -------");
    +        }
    +    }
    +
    +    public buildScene():void{
    +
    +        //check if the seed is not empty
    +        if(this.seed.length==0)
    +        {
    +            console.log("array was empty");
    +            return;
    +        }
    +        
    +        //check if the scene has already been built
    +        if(this.gameObject.children.length>0) 
    +        {
    +            console.log("Scene already present");
    +            return;
    +        }
    +    
    +        // Create cubes at each position of the random walk 
    +        for(let i=0; i<this.seed.length; i++)
    +        {
    +            const option = new InstantiateOptions();
    +            option.context = this.context;
    +            option.parent=this.gameObject;
    +            option.position = this.seed[i];
    +            
    +            if(this.prefab!=null)
    +            {
    +                const cube = GameObject.instantiate(this.prefab, option) as GameObject;
    +            }
    +        }
    +
    +        console.log("----------- Scene Built ---------");
    +        
    +    }
    +
    +    private getRandomDirection(): Vector3 {
    +        const x = Math.random() < 0.5 ? -1 : 1;
    +        const y = Math.random() < 0.5 ? -1 : 1;
    +        const z = Math.random() < 0.5 ? -1 : 1;
    +        return new Vector3(x, y, z);
    +    }
    +
    +}

    The above script is placed on an object (any Transform) and will generate an array of unique Vector3 positions for a specified length (seedSize) after generateSeed() is called (In this case it is called from a button: generateButton).

    Once generated it will send the array to the server and build the scene. The building process consist of instantiating the prefab at each Vector3 position of the seed (this.seed) array.

    Any user joining the same room after a seed has been generated and sent, will receive the seed from the server and trigger the callback onDataReceived() which will cache the seed array, disable the button, and build the scene with the prefab, according to the seed.

    This gives a way to generate a scene and communicate the seed of that scene, for each user to build locally.

    This was the solution I chose which worked better than instantiating a complex scene (>400 objects) with instantiateSynced which would occasionally cause bugs.

    `,14))])}const g=t(e,[["render",r],["__file","network-instantiation-of-multiple-objects.html.vue"]]),y=JSON.parse('{"path":"/community/contributions/web3kev/network-instantiation-of-multiple-objects","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/web3kev: network instantiation of multiple objects.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{g as comp,y as data}; diff --git a/assets/networking.html-Ccq0lod9.js b/assets/networking.html-Ccq0lod9.js new file mode 100644 index 000000000..c5ba50976 --- /dev/null +++ b/assets/networking.html-Ccq0lod9.js @@ -0,0 +1,62 @@ +import{_ as s,o as a,c as e,e as n}from"./app-CRZRGfEE.js";const t="/docs/imgs/networking_absolute.webp",l={};function h(k,i){return a(),e("div",null,i[0]||(i[0]=[n(`

    Networking

    Access to core networking functionality can be obtained by using this.context.connection from a component. The default backend server connects users to rooms. Users in the same room will share state and receive messages from each other.

    Networking is currently based on websockets and sending either json strings (for infrequent updates) or flatbuffers (for frequent updates). Continue reading below for more details:

    Using Multiplayer

    • Enable Networking
      Add a SyncedRoom component.

    • Enable Desktop Viewer Sync
      Add a SyncedCamera component.

    • Enable XR Avatar Sync
      Add a WebXRSync component.

    • Enable Voice Chat
      Add a VoIP component.

    • Enable Screensharing
      Add a ScreenCapture component.

    Core Components

    • SyncedRoom โ€” handles networking connection and connection to a room.
      This can also be done by code using the networking api accessible from this.context.connection
    • SyncedTransform โ€” handles synchronizing transforms
    • SyncedCamera โ€” spawns a prefab for any user connected to the room which will follow their position
    • WebXRSync โ€” handles synchronization for AR and VR users
    • VoIP โ€” handles voice-over-IP audio connections, microphone access etc. between users
    • Networking โ€” use to customize the server backend url

    Manual Networking

    Sending

    Send a json message to all users in the same room:
    this.context.connection.send(key:string, data: IModel | object | boolean | string | number | null)

    Send a flatbuffer binary array to all users in the same room:
    this.context.connect.sendBinary(arr:Uint8Array)

    Persistence

    When sending an object containing a guid field it will be saved in the persistant storage and automatically sent to users that connect later or come back later to the site (e.g. to restore state).
    To delete state for a specific guid from the backend storage you can use delete-state as the key and provide an object with { guid: "guid_to_delete" }

    Receiving

    Subscribe to json events / listen to events in the room using a specific key
    this.context.connection.beginListen(key:string, callback:(data) => void)
    Unsubscribe with stopListening

    Subscribe to flatbuffer binary events
    this.context.connection.beginListenBinrary(identifier:string, callback:(data : ByteBuffer) => void)
    Unsubscribe with stopListenBinary

    Common Events

    Room Events
    this.context.beginListen(RoomEvents.JoinedRoom, () => { })Listen to the event when you have joined a networked room
    this.context.beginListen(RoomEvents.LeftRoom, () => { })Listen to the event when you have left a networked room
    this.context.beginListen(RoomEvents.UserJoinedRoom, () => { })Listen to the event when another user has joined your networked room
    this.context.beginListen(RoomEvents.UserLeftRoom, () => { })Listen to the event when another user has left your networked room

    Auto Networking (experimental)

    To automatically network fields in a component you can just decorate a field with a @syncField() decorator (note: you need to have experimentalDecorators: true in your tsconfig.json file for it to work)

    Example Code

    Automatically network a color field. The following script also changes the color randomly on click

    import { Behaviour, IPointerClickHandler, PointerEventData, Renderer, RoomEvents, delay, serializable, showBalloonMessage, syncField } from "@needle-tools/engine";
    +import { Color } from "three"
    +
    +export class Networking_ClickToChangeColor extends Behaviour implements IPointerClickHandler {
    +
    +    // START MARKER network color change syncField
    +    /** syncField does automatically send a property value when it changes */
    +    @syncField(Networking_ClickToChangeColor.prototype.onColorChanged)
    +    @serializable(Color)
    +    color!: Color;
    +
    +    private onColorChanged() {
    +        // syncField will network the color as a number, so we need to convert it back to a Color when we receive it
    +        if (typeof this.color === "number")
    +            this.color = new Color(this.color);
    +        this.setColorToMaterials();
    +    }
    +    // END MARKER network color change syncField
    +
    +    /** called when the object is clicked and does generate a random color */
    +    onPointerClick(_: PointerEventData) {
    +        const randomColor = new Color(Math.random(), Math.random(), Math.random());
    +        this.color = randomColor;
    +    }
    +
    +    onEnable() {
    +        this.setColorToMaterials();
    +    }
    +
    +    private setColorToMaterials() {
    +        const renderer = this.gameObject.getComponent(Renderer);
    +        if (renderer) {
    +            for (let i = 0; i < renderer.sharedMaterials.length; i++) {
    +                // we clone the material so that we don't change the original material
    +                // just for demonstration purposes, you can also change the original material
    +                const mat = renderer.sharedMaterials[i]?.clone();
    +                renderer.sharedMaterials[i] = mat;
    +                if (mat && "color" in mat)
    +                    mat.color = this.color;
    +            }
    +        }
    +        else console.warn("No renderer found", this.gameObject)
    +    }
    +
    +}

    Simple networking of a number

    import { Behaviour, syncField, IPointerClickHandler } from "@needle-tools/engine"
    +
    +export class AutoFieldSync extends Behaviour implements IPointerClickHandler {
    +
    +    // Use \`@syncField\` to automatically network a field. 
    +    // You can optionally assign a method or method name to be called when the value changes
    +    @syncField("myValueChanged")
    +    mySyncedValue?: number = 1;
    +    
    +    private myValueChanged() {
    +       console.log("My value changed", this.mySyncedValue);
    +    }
    +    
    +    onPointerClick() {
    +       this.mySyncedValue = Math.random();
    +    }
    +}

    Flatbuffers for your own components

    Networking Package

    Needle Engine currently uses its own networking package hosted on npm. By default if not configured differently using the Networking component Needle Engine will connect to a server running on Glitch.

    It can be added to your own fastiy or express server running on any server for example by adding the following code on your server after installing the package:

    import networking from "@needle-tools/needle-tiny-networking-ws";
    +networking.startServerFastify(fastifyApp, { endpoint: "/socket" });

    The following options are available:

    endpoint stringrelative path to the websocket endpoint (e.g. /socket)
    maxUsers numberAmount of users allowed per room
    defaultUserTimeout numberTimeout length in seconds until a user is kicked from a room (if no ping is received). Defaults to 30 seconds

    Networking on Glitch

    When deploying your app to Glitch, we include a simple networking backend that is great for prototyping and small deployments (~15-20 people at the same time). You can later update to a bigger/better/stronger networking solution if required.

    Limitations

    • approx. 15-20 people maximum โ€“ afterwards the small default Glitch server instance becomes slow

    Local Networking

    For testing and development purposes it can be desired to run the needle engine networking package on a local server. We have prepared a repository that is setup to host the websocket package and to make that easy for you. Please follow the instructions in the linked repository:

    Hosting your own Networking Server

    You can also deploy your own networking server on e.g. google cloud. For further instructions please refer to the description found here: Local Networking Repository

    If you want to use a different server for your local development and your hosted development (and the hosted server is not the same as your needle engine deployed website) then you can also enter a absolute URL in the Networking component URL field as well:

    Needle Engine Networking component with networking server hosted elswhere

    peerjs

    Needle Engine Screencapture / Screensharing and Voip components use peerjs for networking audio and video.

    Customizing peerjs options

    • If you want to modify the default peerjs options you can call setPeerOptions(opts: PeerjsOptions) with your custom options. This can be used to modify the hosting provider in case where you host your own peerjs server.
    ',44)]))}const o=s(l,[["render",h],["__file","networking.html.vue"]]),p=JSON.parse('{"path":"/networking.html","title":"Networking","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/networking.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[{"level":2,"title":"Using Multiplayer","slug":"using-multiplayer","link":"#using-multiplayer","children":[]},{"level":2,"title":"Core Components","slug":"core-components","link":"#core-components","children":[]},{"level":2,"title":"Manual Networking","slug":"manual-networking","link":"#manual-networking","children":[{"level":3,"title":"Sending","slug":"sending","link":"#sending","children":[]},{"level":3,"title":"Receiving","slug":"receiving","link":"#receiving","children":[]}]},{"level":2,"title":"Auto Networking (experimental)","slug":"auto-networking-experimental","link":"#auto-networking-experimental","children":[]},{"level":2,"title":"Flatbuffers for your own components","slug":"flatbuffers-for-your-own-components","link":"#flatbuffers-for-your-own-components","children":[]},{"level":2,"title":"Networking Package","slug":"networking-package","link":"#networking-package","children":[]},{"level":2,"title":"Networking on Glitch","slug":"networking-on-glitch","link":"#networking-on-glitch","children":[{"level":3,"title":"Limitations","slug":"limitations","link":"#limitations","children":[]}]},{"level":2,"title":"Local Networking","slug":"local-networking","link":"#local-networking","children":[]},{"level":2,"title":"Hosting your own Networking Server","slug":"hosting-your-own-networking-server","link":"#hosting-your-own-networking-server","children":[]},{"level":2,"title":"peerjs","slug":"peerjs","link":"#peerjs","children":[{"level":3,"title":"Customizing peerjs options","slug":"customizing-peerjs-options","link":"#customizing-peerjs-options","children":[]}]}],"git":{"updatedTime":1726585195000},"filePathRelative":"networking.md"}');export{o as comp,p as data}; diff --git a/assets/os-link-CAGZ994T.js b/assets/os-link-CAGZ994T.js new file mode 100644 index 000000000..ff7d52dec --- /dev/null +++ b/assets/os-link-CAGZ994T.js @@ -0,0 +1 @@ +import{_ as s,o as e,c as n,f as o,d as l,t as u}from"./app-CRZRGfEE.js";const _={props:{text:String,generic_url:String,windows_url:String,osx_url:String,osx_silicon_url:String,linux_url:String},methods:{getUrl:function(){const r=navigator.userAgent;if(r.indexOf("Windows")!==-1){if(this.windows_url)return this.windows_url}else if(r.indexOf("Mac")!==-1){if(this.osx_silicon_url&&r.indexOf("Intel")===-1)return this.osx_silicon_url;if(this.osx_url)return this.osx_url}else if(r.indexOf("Linux")!==-1){if(this.linux_url)return this.linux_url;if(this.osx_url)return this.osx_url}return this.generic_url??this.windows_url}}},f=["href"];function c(r,x,i,a,d,t){return e(),n("a",{href:t.getUrl()},[o(r.$slots,"default",{},()=>[l(u(i.text),1)])],8,f)}const g=s(_,[["render",c],["__file","os-link.vue"]]);export{g as default}; diff --git a/assets/project-structure.html-DAYDA0w3.js b/assets/project-structure.html-DAYDA0w3.js new file mode 100644 index 000000000..681af4e3d --- /dev/null +++ b/assets/project-structure.html-DAYDA0w3.js @@ -0,0 +1 @@ +import{_ as u,r as i,o as d,c as s,a as t,b as r,w as o,d as l}from"./app-CRZRGfEE.js";const p={};function a(f,e){const n=i("RouteLink");return d(),s("div",null,[e[33]||(e[33]=t("h1",{id:"needle-engine-project-structure",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#needle-engine-project-structure"},[t("span",null,"Needle Engine Project Structure")])],-1)),e[34]||(e[34]=t("h3",{id:"web-project-files",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#web-project-files"},[t("span",null,"Web Project Files")])],-1)),t("table",null,[e[8]||(e[8]=t("thead",null,[t("tr",null,[t("th"),t("th")])],-1)),t("tbody",null,[e[2]||(e[2]=t("tr",null,[t("td",null,[t("strong",null,"Needle Engine")]),t("td")],-1)),t("tr",null,[t("td",null,[r(n,{to:"/reference/needle-config-json.html"},{default:o(()=>e[0]||(e[0]=[t("code",null,"needle.config.json",-1)])),_:1})]),e[1]||(e[1]=t("td",null,"Configuration for Needle Engine builds and integrations",-1))]),e[3]||(e[3]=t("tr",null,[t("td",null,[t("strong",null,"Ecosystem")]),t("td")],-1)),e[4]||(e[4]=t("tr",null,[t("td",null,[t("code",null,"package.json")]),t("td",null,"Project configuration containing name, version, dependencies and scripts")],-1)),e[5]||(e[5]=t("tr",null,[t("td",null,[t("code",null,"tsconfig.json")]),t("td",null,"Typescript compiler configuration")],-1)),e[6]||(e[6]=t("tr",null,[t("td",null,[t("code",null,".gitignore")]),t("td",null,"Files and folders to be ignored in git")],-1)),e[7]||(e[7]=t("tr",null,[t("td",null,[t("code",null,"vite.config.js")]),t("td",null,[l("Contains vite specific configuration."),t("br"),l("It also adds the Needle Engine vite plugins.")])],-1))])]),e[35]||(e[35]=t("h3",{id:"default-vite-project-structure",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#default-vite-project-structure"},[t("span",null,"Default Vite project structure")])],-1)),e[36]||(e[36]=t("p",null,[l("Our main project template uses the superfast "),t("a",{href:"https://vitejs.dev/",target:"_blank",rel:"noopener noreferrer"},"vite"),l(" bundler. The following shows the structure of the Vite template that we created and ship (altough it is possible to adapt it to your own needs).")],-1)),t("table",null,[e[27]||(e[27]=t("thead",null,[t("tr",null,[t("th"),t("th")])],-1)),t("tbody",null,[e[17]||(e[17]=t("tr",null,[t("td",null,[t("strong",null,"Folders")]),t("td")],-1)),e[18]||(e[18]=t("tr",null,[t("td",null,[t("code",null,"assets/")]),t("td",null,[l("The asset folder contains exported assets from Unity. E.g. generated "),t("code",null,"gltf"),l(" files, audio or video files. It is not recommended to manually add files to "),t("code",null,"assets"),l(" as it will get cleared on building the distribution for the project.")])],-1)),e[19]||(e[19]=t("tr",null,[t("td",null,[t("code",null,"include/")]),t("td",null,"(optional) - If you have custom assets that you need to reference/load add them to the include directory. On build this directory will be copied to the output folder.")],-1)),e[20]||(e[20]=t("tr",null,[t("td",null,[t("code",null,"src/generated/")]),t("td",null,"The generated javascript code. Do not edit manually!")],-1)),e[21]||(e[21]=t("tr",null,[t("td",null,[t("code",null,"src/scripts/")]),t("td",null,"Your project specific scripts / components")],-1)),e[22]||(e[22]=t("tr",null,[t("td",null,[t("code",null,"src/styles/")]),t("td",null,"Stylesheets")],-1)),t("tr",null,[e[12]||(e[12]=t("td",null,[t("code",null,"*")],-1)),t("td",null,[e[10]||(e[10]=l("You can add any new folders here as you please. Make sure to ")),r(n,{to:"/reference/needle-config-json.html"},{default:o(()=>e[9]||(e[9]=[l("copy")])),_:1}),e[11]||(e[11]=l(" them to the output directory when building"))])]),e[23]||(e[23]=t("tr",null,[t("td",null,[t("strong",null,"Files")]),t("td")],-1)),e[24]||(e[24]=t("tr",null,[t("td",null,[t("code",null,"index.html")]),t("td",null,"The landing- or homepage of your website")],-1)),e[25]||(e[25]=t("tr",null,[t("td",null,[t("code",null,"vite.config")]),t("td",null,[l("The "),t("a",{href:"https://vitejs.dev/config/",target:"_blank",rel:"noopener noreferrer"},"vite config"),l(". Settings for building the distribution and hosting the development server are made here. It is usually not necessary to edit these settings.")])],-1)),e[26]||(e[26]=t("tr",null,[t("td",null,[t("code",null,"src/main.ts")]),t("td",null,[l("Included from "),t("code",null,"index.html"),l(" and importing "),t("code",null,"needle-engine")])],-1)),t("tr",null,[e[16]||(e[16]=t("td",null,[t("code",null,"*")],-1)),t("td",null,[e[14]||(e[14]=l("You can add any new files here as you please. Make sure to ")),r(n,{to:"/reference/needle-config-json.html"},{default:o(()=>e[13]||(e[13]=[l("copy")])),_:1}),e[15]||(e[15]=l(" them to the output directory when building (unless they are just being used during development)"))])])])]),e[37]||(e[37]=t("p",null,"Our exporter can be used with other project structures as well, vite is just our go-to frontend bundling tool because of its speed. Feel free to set up your JavaScript project as you like.",-1)),t("p",null,[r(n,{to:"/html.html"},{default:o(()=>e[28]||(e[28]=[l("Learn more in the docs about bundling and usage with other frameworks")])),_:1})]),e[38]||(e[38]=t("hr",null,null,-1)),e[39]||(e[39]=t("h4",{id:"continue-reading",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#continue-reading"},[t("span",null,"Continue Reading")])],-1)),t("ul",null,[t("li",null,[r(n,{to:"/getting-started/for-unity-developers.html"},{default:o(()=>e[29]||(e[29]=[l("Typescript Guide for Unity Developers")])),_:1})]),t("li",null,[r(n,{to:"/getting-started/typescript-essentials.html"},{default:o(()=>e[30]||(e[30]=[l("Typescript Essentials")])),_:1})]),t("li",null,[r(n,{to:"/scripting.html"},{default:o(()=>e[31]||(e[31]=[l("Writing custom scripts")])),_:1})]),t("li",null,[r(n,{to:"/everywhere-actions.html"},{default:o(()=>e[32]||(e[32]=[l("Everywhere Actions")])),_:1})])])])}const m=u(p,[["render",a],["__file","project-structure.html.vue"]]),j=JSON.parse('{"path":"/project-structure.html","title":"Web Project Structure","lang":"en-US","frontmatter":{"title":"Web Project Structure","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/preview.jpeg"}],["meta",{"name":"og:description","content":"---"}]],"description":"---"},"headers":[{"level":3,"title":"Web Project Files","slug":"web-project-files","link":"#web-project-files","children":[]},{"level":3,"title":"Default Vite project structure","slug":"default-vite-project-structure","link":"#default-vite-project-structure","children":[]}],"git":{"updatedTime":1727723055000},"filePathRelative":"project-structure.md"}');export{m as comp,j as data}; diff --git a/assets/quicklook-vertical-image-tracker.html-C2obMcDm.js b/assets/quicklook-vertical-image-tracker.html-C2obMcDm.js new file mode 100644 index 000000000..371976a97 --- /dev/null +++ b/assets/quicklook-vertical-image-tracker.html-C2obMcDm.js @@ -0,0 +1,43 @@ +import{_ as t,r as n,o as h,c as l,a as s,b as k,e}from"./app-CRZRGfEE.js";const p={};function r(d,i){const a=n("contribution-header");return h(),l("div",null,[i[0]||(i[0]=s("p",null,[s("a",{href:"/docs/community/contributions"},"Overview")],-1)),k(a,{url:"https://github.com/ericcraft-mh",author:"ericcraft-mh",page:"/docs/community/contributions/ericcraft-mh",profileImage:"https://avatars.githubusercontent.com/u/99364056?s=100&v=4",githubUrl:"https://github.com/needle-tools/needle-engine-support/discussions/191",title:"QuickLook Vertical Image Tracker",gradient:"True"}),i[1]||(i[1]=e(`

    In cases in which you are using QuickLook Image Tracker and Vertical Imagery you will need to correct the orientation of the model. As noted on the Detecting Images in an AR Experience page:

    SCNPlane is vertically oriented in its local coordinate space, but ARImageAnchor assumes the image is horizontal in its local space, so rotate the plane to match.

    import { Behaviour, GameObject, serializable, USDZExporter } from "@needle-tools/engine";
    +import { Object3D, Euler } from "three";
    +
    +export class QuickLookObjectsToFix extends Behaviour {
    +
    +    @serializable(Object3D)
    +    objectToFix!: Object3D;
    +
    +    private usdzExporter!: USDZExporter;
    +    private startRot: Euler = new Euler();
    +
    +    onEnable() {
    +        this.usdzExporter = GameObject.findObjectOfType(USDZExporter)!;
    +        this.startRot = this.objectToFix.rotation;
    +        this.subscribeToBeforeExportEvent();
    +    }
    +
    +    onDisable() {
    +        this.unsubscribeFromBeforeExportEvent();
    +    }
    +
    +    private subscribeToBeforeExportEvent() {
    +        this.usdzExporter.addEventListener("before-export", this.onBeforeExport);
    +        this.usdzExporter.addEventListener("after-export", this.onAfterExport);
    +    }
    +
    +    private unsubscribeFromBeforeExportEvent() {
    +        this.usdzExporter.removeEventListener("before-export", this.onBeforeExport);
    +        this.usdzExporter.removeEventListener("after-export", this.onAfterExport);
    +    }
    +
    +    private onBeforeExport = () => {
    +        this.objectToFix.updateMatrixWorld();
    +        this.objectToFix.rotation.x = -Math.PI / 2;
    +        this.objectToFix.updateMatrixWorld();
    +    }
    +
    +    private onAfterExport = () => {
    +        this.objectToFix.updateMatrixWorld();
    +        this.objectToFix.setRotationFromEuler(this.startRot);
    +        this.objectToFix.updateMatrixWorld();
    +    }
    +}

    Thanks to llllkatjallll as their Set fallback material for USDZ exporter solution helped me come up with a working solution for this.

    EDIT: Code cleanup and fixes.

    `,5))])}const g=t(p,[["render",r],["__file","quicklook-vertical-image-tracker.html.vue"]]),y=JSON.parse('{"path":"/community/contributions/ericcraft-mh/quicklook-vertical-image-tracker","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/ericcraft mh: quicklook vertical image tracker.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{g as comp,y as data}; diff --git a/assets/quoteslides-Jbcw9khk.js b/assets/quoteslides-Jbcw9khk.js new file mode 100644 index 000000000..125f38471 --- /dev/null +++ b/assets/quoteslides-Jbcw9khk.js @@ -0,0 +1 @@ +import{_ as n,p as l,q as a,o as d,c,f as i}from"./app-CRZRGfEE.js";const r=l({setup(){a(()=>{const o=document.querySelector(".quotes");o.style.display="flex";const e=document.querySelectorAll(".quotes > div");for(let s=0;s{e[t].style.display="none",t=(t+1)%e.length,e[t].style.display="block"},5e3)})}}),u={class:"quotes"};function f(o,e,t,s,p,_){return d(),c("div",u,[i(o.$slots,"default",{},void 0,!0)])}const y=n(r,[["render",f],["__scopeId","data-v-96af3692"],["__file","quoteslides.vue"]]);export{y as default}; diff --git a/assets/removeserviceworker-CWQpv6MD.js b/assets/removeserviceworker-CWQpv6MD.js new file mode 100644 index 000000000..a708778c2 --- /dev/null +++ b/assets/removeserviceworker-CWQpv6MD.js @@ -0,0 +1 @@ +import{_ as t}from"./app-CRZRGfEE.js";console.log("ServiceWorker:",navigator.serviceWorker);var o;(o=navigator.serviceWorker)==null||o.getRegistrations().then(r=>{for(const e of r)console.log("ServiceWorker unregistered:",e),e.unregister()});const s={};function n(r,e,i,c,a,v){return null}const f=t(s,[["render",n],["__file","removeserviceworker.vue"]]);export{f as default}; diff --git a/assets/robyer1.html-DKUQa3GZ.js b/assets/robyer1.html-DKUQa3GZ.js new file mode 100644 index 000000000..caf412450 --- /dev/null +++ b/assets/robyer1.html-DKUQa3GZ.js @@ -0,0 +1,65 @@ +import{_ as n,r as k,o as r,c as p,b as h,w as a,a as i,d as s}from"./app-CRZRGfEE.js";const d={};function C(y,t){const l=k("contribution-preview"),e=k("contributions-author");return r(),p("div",null,[h(e,{overviewLink:"/docs/community/contributions",name:"ROBYER1",url:"https://github.com/ROBYER1",profileImage:"https://avatars.githubusercontent.com/u/10745594?s=100&u=daf2c8b5dad729e556ae2a01c721672b24bc108a&v=4",githubUrl:"https://github.com/ROBYER1"},{default:a(()=>[h(l,{title:"Microphone access in a browser window (and streamed playback)",pageUrl:"/docs/community/contributions/robyer1/microphone-access-in-a-browser-window-and-streamed-playback"},{default:a(()=>t[0]||(t[0]=[i("p",null,"A simple script to show how to request access to, then access a microphone device and also play back the audio stream to debug it. A useful starting point for making an experience revolving around microphone access.",-1),i("div",{class:"language-ts","data-highlighter":"shiki","data-ext":"ts","data-title":"ts",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[i("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[i("code",null,[i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Behaviour "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "@needle-tools/engine"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"export"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," class"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Microphone"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," extends"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Behaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," start"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"getLocalStream"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," public"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," el"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Element"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," attachStream"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"("),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"stream"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," el"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," options"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," var"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," item"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," var"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," URL "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," window"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"URL"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," var"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," element "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," el"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," var"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," opts "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," autoplay"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," true"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},",")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," mirror"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," false"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},",")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," muted"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," false"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},",")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," audio"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," false"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},",")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," disableContextMenu"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," false"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},",")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," };")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," (options) "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," for"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," (item "),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"in"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," options) "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," opts[item] "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," options[item]"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ("),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"!"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"element) "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," element "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," document"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"createElement"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(opts"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"audio "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "audio"'),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," :"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "video"'),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," else"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," (element"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"tagName"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"toLowerCase"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"() "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"==="),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "audio"'),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},") "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," opts"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"audio "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," true"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," (opts"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"autoplay) element"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"autoplay "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "autoplay"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," (opts"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"muted) element"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"muted "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," true"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ("),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"!"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"opts"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"audio "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"&&"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," opts"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"mirror) "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ["),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'""'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "moz"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "webkit"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "o"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "ms"'),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"]"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"forEach"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"function"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," ("),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"prefix"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," var"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," styleName "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," prefix "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," prefix "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"+"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "Transform"'),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," :"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "transform"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," element"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"style[styleName] "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "scaleX(-1)"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," element"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"srcObject "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," stream"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," return"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," element"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," getLocalStream"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," navigator"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"mediaDevices")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," ."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"getUserMedia"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," video"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," false"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},",")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," audio"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," true"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},",")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," ."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"then"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"("),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"stream"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},")"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," =>"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," var"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," doesnotexist "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," !"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"el"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"el "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"attachStream"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(stream"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"el"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," audio"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," true"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},",")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," autoplay"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," true"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},",")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," (doesnotexist) document"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"body"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"appendChild"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"el)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," ."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"catch"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"("),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"err"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},")"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," =>"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," console"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"log"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"u got an error:"'),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," +"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," err)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}")])])])],-1)])),_:1}),h(l,{title:"AR Move/Scale/Rotate Controls for Needle on Mobile",pageUrl:"/docs/community/contributions/robyer1/ar-move-scale-rotate-controls-for-needle-on-mobile"},{default:a(()=>t[1]||(t[1]=[i("p",null,"This is live for preview over at https://needle-ar.glitch.me/",-1),i("p",null,"I will share a github repository if others are interested in collaborating on this, so far I have just sorted functionality for spawning a product model and a floor plane that is large to move it around on. Scale and Rotate work with two finger touches.",-1),i("p",null,"I am hoping to figure out how to show and raycast against AR detected planes over here which will remove the need for a large floor plane to raycast against โ Unknown",-1),i("p",null,"Public Github Repository: https://github.com/ROBYER1/Needle-AR-Demo",-1)])),_:1})]),_:1})])}const F=n(d,[["render",C],["__file","robyer1.html.vue"]]),o=JSON.parse('{"path":"/community/contributions/robyer1","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/contributions: robyer1.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{F as comp,o as data}; diff --git a/assets/sample-rKQKOG12.js b/assets/sample-rKQKOG12.js new file mode 100644 index 000000000..2fd87573a --- /dev/null +++ b/assets/sample-rKQKOG12.js @@ -0,0 +1 @@ +import{_ as c,o as r,c as o,a as l,g as i}from"./app-CRZRGfEE.js";const d={props:{src:String,split:{type:Boolean,default:!1},noRoom:{type:Boolean,default:!1}},data(){return{sanitizedUrl:""}},watch:{src:{immediate:!0,handler(n){const e=new URL(n),t=Math.random().toString(36).substring(2,6);e.searchParams.delete("room"),this.noRoom||e.searchParams.append("room",`needle_docs_${t}`),typeof window<"u"&&new URL(window.location.href),e.searchParams.append("hideClose",""),e.searchParams.append("utm_source","needle_docs"),e.searchParams.append("utm_content","sample_embed"),this.sanitizedUrl=e.toString()}}},mounted(){const n=e=>{if(!e||!e.contentWindow)return;const t=e.contentWindow.document.getElementsByTagName("iframe")[0];if(t){const a=t.contentWindow.document.querySelector("needle-engine");a&&(a.style.touchAction="pan-y")}};n(this.$refs.frame1),n(this.$refs.frame2)}},m=["src"],p=["src"];function u(n,e,t,s,a,f){return r(),o("div",null,[l("iframe",{src:a.sanitizedUrl,ref:"frame1",allow:"xr; xr-spatial-tracking; camera; microphone; fullscreen; display-capture"},null,8,m),t.split===!0?(r(),o("iframe",{key:0,src:a.sanitizedUrl,ref:"frame2",allow:"xr; xr-spatial-tracking; camera; microphone; fullscreen; display-capture"},null,8,p)):i("",!0)])}const h=c(d,[["render",u],["__scopeId","data-v-b3cc3f9a"],["__file","sample.vue"]]);export{h as default}; diff --git a/assets/samples-and-modules.html-BqywFF0Q.js b/assets/samples-and-modules.html-BqywFF0Q.js new file mode 100644 index 000000000..13aa51f59 --- /dev/null +++ b/assets/samples-and-modules.html-BqywFF0Q.js @@ -0,0 +1 @@ +import{_ as s,r as o,o as t,c as d,b as p,a as e,d as l}from"./app-CRZRGfEE.js";const i={};function r(m,a){const n=o("sample");return t(),d("div",null,[p(n,{src:"https://engine.needle.tools/samples-uploads/physics-cannon/"}),a[0]||(a[0]=e("h2",{id:"samples-to-download-and-play",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#samples-to-download-and-play"},[e("span",null,"Samples to download and play")])],-1)),a[1]||(a[1]=e("p",null,[l("View all samples at "),e("a",{href:"https://engine.needle.tools/samples",target:"_blank",rel:"noopener noreferrer"},"engine.needle.tools/samples"),l(" with a live preview and links for download and installation.")],-1))])}const w=s(i,[["render",r],["__file","samples-and-modules.html.vue"]]),h=JSON.parse('{"path":"/samples-and-modules.html","title":"Samples Projects","lang":"en-US","frontmatter":{"title":"Samples Projects","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/samples projects.png"}],["meta",{"name":"og:description","content":"---\\nView all samples at engine.needle.tools/samples with a live preview and links for download and installation.\\nScripting Examples

    Video tutorial: How to write custom components

    Below you will find a few basic scripts as a quick reference.

    We also offer a lot of sample scenes and complete projects that you can download and use as a starting point:

    Basic component

    ',6)),a(t,{file:"@code/basic-component.ts"}),i[2]||(i[2]=s(`
    import { Behaviour, serializable } from "@needle-tools/engine"
    +import { Object3D } from "three"
    +
    +export class MyComponent extends Behaviour {
    +
    +    @serializable(Object3D)
    +    myObjectReference?: Object3D;
    +
    +    start() {
    +        console.log("Hello world", this);
    +    }
    +
    +    update() {
    +        this.gameObject.rotateY(this.context.time.deltaTime);
    +    }
    +}

    see scripting for all component events

    Reference an Object from Unity

    import { Behaviour, serializable } from "@needle-tools/engine";
    +import { Object3D } from "three"
    +
    +export class MyClass extends Behaviour {
    +    // this will be a "Transform" field in Unity
    +    @serializable(Object3D) 
    +    myObjectReference: Object3D | null = null;
    +    
    +    // this will be a "Transform" array field in Unity
    +    // Note that the @serializable decorator contains the array content type! (Object3D and not Object3D[])
    +    @serializable(Object3D) 
    +    myObjectReferenceList: Object3D[] | null = null;
    +}

    Reference and load an asset from Unity (Prefab or SceneAsset)

    import { Behaviour, serializable, AssetReference } from "@needle-tools/engine";
    +
    +export class MyClass extends Behaviour {
    +
    +    // if you export a prefab or scene as a reference from Unity you'll get a path to that asset
    +    // which you can de-serialize to AssetReference for convenient loading
    +    @serializable(AssetReference)
    +    myPrefab?: AssetReference;
    +    
    +    async start() {
    +      // directly instantiate
    +      const myInstance = await this.myPrefab?.instantiate();
    +
    +      // you can also just load and instantiate later
    +      // const myInstance = await this.myPrefab.loadAssetAsync();
    +      // this.gameObject.add(myInstance)
    +      // this is useful if you know that you want to load this asset only once because it will not create a copy
    +      // since \`\`instantiate()\`\` does create a copy of the asset after loading it
    +    }  
    +}

    Reference and load scenes from Unity

    Tips

    Find a working example in our samples to download and try

    import { Behaviour, serializable, AssetReference } from "@needle-tools/engine";
    +
    +export class LoadingScenes extends Behaviour {
    +    // tell the component compiler that we want to reference an array of SceneAssets
    +    // @type UnityEditor.SceneAsset[]
    +    @serializable(AssetReference)
    +    myScenes?: AssetReference[];
    +
    +    async awake() {
    +        if (!this.myScenes) {
    +            return;
    +        }
    +        for (const scene of this.myScenes) {
    +            // check if it is assigned in unity
    +            if(!scene) continue;
    +            // load the scene once
    +            const myScene = await scene.loadAssetAsync();
    +            // add it to the threejs scene
    +            this.gameObject.add(myScene);
    +            
    +            // of course you can always just load one at a time
    +            // and remove it from the scene when you want
    +            // myScene.removeFromParent();
    +            // this is the same as scene.asset.removeFromParent()
    +        }
    +    }
    +
    +    onDestroy(): void {
    +        if (!this.myScenes) return;
    +        for (const scene of this.myScenes) {
    +            scene?.unload();
    +        }
    +    }
    +}

    Receive Clicks on Objects

    Add this script to any object in your scene that you want to be clickable. Make sure to also have an ObjectRaycaster component in the parent hierarchy of that object.

    `,12)),a(t,{file:"@code/component-click.ts"},{default:e(()=>i[0]||(i[0]=[r(" test ")])),_:1}),i[3]||(i[3]=s(`
    import { Behaviour, IPointerClickHandler, PointerEventData, showBalloonMessage } from "@needle-tools/engine";
    +
    +export class ClickExample extends Behaviour implements IPointerClickHandler {
    +
    +    // Make sure to have an ObjectRaycaster component in the parent hierarchy
    +    onPointerClick(_args: PointerEventData) {
    +        showBalloonMessage("Clicked " + this.name);
    +    }
    +}

    Networking Clicks on Objects

    Add this script to any object in your scene that you want to be clickable. Make sure to also have an ObjectRaycaster component in the parent hierarchy of that object.
    The component will send the received click to all connected clients and will raise an event that you can then react to in your app. If you are using Unity or Blender you can simply assign functions to call to the onClick event to e.g. play an animation or hide objects.

    import { Behaviour, EventList, IPointerClickHandler, PointerEventData, serializable } from "@needle-tools/engine";
    +
    +export class SyncedClick extends Behaviour implements IPointerClickHandler {
    +
    +    @serializable(EventList)
    +    onClick!: EventList;
    +
    +    onPointerClick(_args: PointerEventData) {
    +        console.log("SEND CLICK");
    +        this.context.connection.send("clicked/" + this.guid);
    +        this.onClick?.invoke();
    +    }
    +
    +    onEnable(): void {
    +        this.context.connection.beginListen("clicked/" + this.guid, this.onRemoteClick);
    +    }
    +    onDisable(): void {
    +        this.context.connection.stopListen("clicked/" + this.guid, this.onRemoteClick);
    +    }
    +
    +
    +    onRemoteClick = () => {
    +        console.log("RECEIVED CLICK");
    +        this.onClick?.invoke();
    +    }
    +    
    +}

    Play Animation on click

    import { Behaviour, serializable, Animation, IPointerClickHandler, PointerEventData } from "@needle-tools/engine";
    +
    +export class PlayAnimationOnClick extends Behaviour implements IPointerClickHandler {
    +
    +    @serializable(Animation)
    +    animation?: Animation;
    +
    +    awake() {
    +        if (this.animation) {
    +            this.animation.playAutomatically = false;
    +            this.animation.loop = false;
    +        }
    +    }
    +
    +    onPointerClick(_args: PointerEventData) {
    +        if (this.animation) {
    +            this.animation.play();
    +        }
    +    }
    +}

    Reference an Animation Clip

    This can be useful if you want to run your custom animation logic.
    You can also export an array of clips.

    import { Behaviour, serializable } from "@needle-tools/engine";
    +import { AnimationClip } from "three"
    +
    +export class ExportAnimationClip extends Behaviour {
    +
    +    @serializable(AnimationClip)
    +    animation?: AnimationClip;
    +
    +    awake() {
    +        console.log("My referenced animation clip", this.animation);
    +    }
    +}

    Create and invoke a UnityEvent

    import { Behaviour, serializable, EventList } from "@needle-tools/engine"
    +
    +export class MyComponent extends Behaviour {
    +
    +    @serializable(EventList)
    +    myEvent? : EventList;
    +
    +    start() {
    +        this.myEvent?.invoke();
    +    }
    +}

    Tips

    EventList events are also invoked on the component level. This means you can also subscribe to the event declared above using myComponent.addEventListener("my-event", evt => {...}) as well.
    This is an experimental feature. Please provide feedback in our forum

    Declare a custom event type

    This is useful for when you want to expose an event to Unity or Blender with some custom arguments (like a string)

    import { Behaviour, serializable, EventList } from "@needle-tools/engine";
    +import { Object3D } from "three";
    +
    +/*
    +Make sure to have a c# file in your project with the following content:
    +
    +using UnityEngine;
    +using UnityEngine.Events;
    +
    +[System.Serializable]
    +public class MyCustomUnityEvent : UnityEvent<string>
    +{
    +}
    +
    +Unity documentation about custom events: 
    +https://docs.unity3d.com/ScriptReference/Events.UnityEvent_2.html
    +
    +*/
    +
    +// Documentation โ†’ https://docs.needle.tools/scripting
    +
    +export class CustomEventCaller extends Behaviour {
    +
    +    // The next line is not just a comment, it defines 
    +    // a specific type for the component generator to use.
    +
    +    //@type MyCustomUnityEvent
    +    @serializable(EventList)
    +    myEvent!: EventList;
    +
    +    // just for testing - could be when a button is clicked, etc.
    +    start() {
    +        this.myEvent.invoke("Hello");
    +    }
    +}
    +
    +export class CustomEventReceiver extends Behaviour {
    +
    +    logStringAndObject(str: string) {
    +        console.log("From Event: ", str);
    +    }
    +}

    Example use:
    20221128-210735_Unity-needle

    Use nested objects and serialization

    You can nest objects and their data. With properly matching @serializable(SomeType) decorators, the data will be serialized and deserialized into the correct types automatically.

    In your typescript component:

    import { Behaviour, serializable } from "@needle-tools/engine";
    +
    +// Documentation โ†’ https://docs.needle.tools/scripting
    +
    +class CustomSubData {
    +    @serializable()
    +    subString: string = "";
    +    
    +    @serializable()
    +    subNumber: number = 0;
    +}
    +
    +class CustomData {
    +    @serializable()
    +    myStringField: string = "";
    +    
    +    @serializable()
    +    myNumberField: number = 0;
    +    
    +    @serializable()
    +    myBooleanField: boolean = false;
    +    
    +    @serializable(CustomSubData)
    +    subData: CustomSubData | undefined = undefined;
    +
    +    someMethod() {
    +        console.log("My string is " + this.myStringField, "my sub data", this.subData)
    +    }
    +}
    +
    +export class SerializedDataSample extends Behaviour {
    +
    +    @serializable(CustomData)  
    +    myData: CustomData | undefined;
    +    
    +    onEnable() {
    +        console.log(this.myData);
    +        this.myData?.someMethod();
    +    }
    +}

    In C# in any script:

    using System;
    +
    +[Serializable]
    +public class CustomSubData
    +{
    +    public string subString;
    +    public float subNumber;
    +}
    +	
    +[Serializable]
    +public class CustomData
    +{
    +    public string myStringField;
    +    public float myNumberField;
    +    public bool myBooleanField;
    +    public CustomSubData subData;
    +}

    Tips

    Without the correct type decorators, you will still get the data, but just as a plain object. This is useful when you're porting components, as you'll have access to all data and can add types as required.

    Use Web APIs

    Tips

    Keep in mind that you still have access to all web apis and npm packages!
    That's the beauty of Needle Engine if we're allowed to say this here ๐Ÿ˜Š

    Display current location

    import { Behaviour, showBalloonMessage } from "@needle-tools/engine";
    +
    +export class WhereAmI extends Behaviour {
    +    start() {
    +        navigator.geolocation.getCurrentPosition((position) => {
    +            console.log("Navigator response:", position);
    +            const latlong = position.coords.latitude + ", " + position.coords.longitude;
    +            showBalloonMessage("You are at\\nLatLong " + latlong);
    +        });
    +    }
    +}

    Display current time using a Coroutine

    import { Behaviour, Text, serializable, WaitForSeconds } from "@needle-tools/engine";
    +
    +export class DisplayTime extends Behaviour {
    +
    +    @serializable(Text)
    +    text?: Text;
    +
    +    onEnable(): void {
    +        this.startCoroutine(this.updateTime())
    +    }
    +
    +    private *updateTime() {
    +        while (true) {
    +            if (this.text) {
    +                this.text.text = new Date().toLocaleTimeString();
    +                console.log(this.text.text)
    +            }
    +            yield WaitForSeconds(1)
    +        }
    +    };
    +}
    `,29)),a(h,{src:"./videos/component-time.mp4",limit_height:""}),i[4]||(i[4]=s(`

    Change custom shader property

    Assuming you have a custom shader with a property name _Speed that is a float value this is how you would change it from a script.
    You can find a live example to download in our samples

    import { Behaviour, serializable } from "@needle-tools/engine";
    +import { Material } from "three";
    +
    +declare type MyCustomShaderMaterial = {
    +   _Speed: number;
    +};
    +
    +export class IncreaseShaderSpeedOverTime extends Behaviour {
    +
    +   @serializable(Material)
    +   myMaterial?: Material & MyCustomShaderMaterial;
    +
    +   update() {
    +       if (this.myMaterial) {
    +           this.myMaterial._Speed *= 1 + this.context.time.deltaTime;
    +           if(this.myMaterial._Speed > 1) this.myMaterial._Speed = .0005;
    +           if(this.context.time.frame % 30 === 0) console.log(this.myMaterial._Speed)
    +       }
    +   }
    +}

    Switching src attribute

    See live example on StackBlitz

    Adding new postprocessing effects

    Make sure to install npm i postprocessing in your web project. Then you can add new effects by deriving from PostProcessingEffect.

    To use the effect add it to the same object as your Volume component.

    Here is an example that wraps the Outline postprocessing effect. You can expose variables and settings as usual as any effect is also just a component in your three.js scene.

    import { EffectProviderResult, PostProcessingEffect, registerCustomEffectType, serializable } from "@needle-tools/engine";
    +import { OutlineEffect } from "postprocessing";
    +import { Object3D } from "three";
    +
    +export class OutlinePostEffect extends PostProcessingEffect {
    +
    +    // the outline effect takes a list of objects to outline
    +    @serializable(Object3D)
    +    selection!: Object3D[];
    +
    +    // this is just an example method that you could call to update the outline effect selection
    +    updateSelection() {
    +        if (this._outlineEffect) {
    +            this._outlineEffect.selection.clear();
    +            for (const obj of this.selection) {
    +                this._outlineEffect.selection.add(obj);
    +            }
    +        }
    +    }
    +
    +
    +    // a unique name is required for custom effects
    +    get typeName(): string {
    +        return "Outline";
    +    }
    +
    +    private _outlineEffect: void | undefined | OutlineEffect;
    +
    +    // method that creates the effect once
    +    onCreateEffect(): EffectProviderResult | undefined {
    +
    +        const outlineEffect = new OutlineEffect(this.context.scene, this.context.mainCamera!);
    +        this._outlineEffect = outlineEffect;
    +        outlineEffect.edgeStrength = 10;
    +        outlineEffect.visibleEdgeColor.set(0xff0000);
    +        for (const obj of this.selection) {
    +            outlineEffect.selection.add(obj);
    +        }
    +
    +        return outlineEffect;
    +    }
    +}
    +// You need to register your effect type with the engine
    +registerCustomEffectType("Outline", OutlinePostEffect);

    Custom ParticleSystem Behaviour

    import { Behaviour, ParticleSystem } from "@needle-tools/engine";
    +import { ParticleSystemBaseBehaviour, QParticle } from "@needle-tools/engine";
    +
    +// Derive your custom behaviour from the ParticleSystemBaseBehaviour class (or use QParticleBehaviour)
    +class MyParticlesBehaviour extends ParticleSystemBaseBehaviour {
    +
    +    // callback invoked per particle
    +    update(particle: QParticle): void {
    +        particle.position.y += 5 * this.context.time.deltaTime;
    +    }
    +}
    +export class TestCustomParticleSystemBehaviour extends Behaviour {
    +    start() {
    +        // add your custom behaviour to the particle system
    +        this.gameObject.getComponent(ParticleSystem)!.addBehaviour(new MyParticlesBehaviour())
    +    }
    +}

    Custom 2D Audio Component

    This is an example how you could create your own audio component.
    For most usecases however you can use the core AudioSource component and don't have to write code.

    import { AudioSource, Behaviour, serializable } from "@needle-tools/engine";
    +
    +// declaring AudioClip type is for codegen to produce the correct input field (for e.g. Unity or Blender)
    +declare type AudioClip = string;
    +
    +export class My2DAudio extends Behaviour {
    +
    +    // The clip contains a string pointing to the audio file - by default it's relative to the GLB that contains the component
    +    // by adding the URL decorator the clip string will be resolved relative to your project root and can be loaded
    +    @serializable(URL)
    +    clip?: AudioClip;
    +
    +    awake() {
    +        // creating a new audio element and playing it
    +        const audioElement = new Audio(this.clip);
    +        audioElement.loop = true;
    +        // on the web we have to wait for the user to interact with the page before we can play audio
    +        AudioSource.registerWaitForAllowAudio(() => {
    +            audioElement.play();
    +        })
    +    }
    +}

    Arbitrary external files

    Use the FileReference type to load external files (e.g. a json file)

    import { Behaviour, FileReference, ImageReference, serializable } from "@needle-tools/engine";
    +
    +export class FileReferenceExample extends Behaviour {
    +
    +    // A FileReference can be used to load and assign arbitrary data in the editor. You can use it to load images, audio, text files... FileReference types will not be saved inside as part of the GLB (the GLB will only contain a relative URL to the file)
    +    @serializable(FileReference)
    +    myFile?: FileReference;
    +    // Tip: if you want to export and load an image (that is not part of your GLB) if you intent to add it to your HTML content for example you can use the ImageReference type instead of FileReference. It will be loaded as an image and you can use it as a source for an <img> tag.
    +
    +    async start() {
    +        console.log("This is my file: ", this.myFile);
    +        // load the file
    +        const data = await this.myFile?.loadRaw();
    +        if (!data) {
    +            console.error("Failed loading my file...");
    +            return;
    +        }
    +        console.log("Loaded my file. These are the bytes:", await data.arrayBuffer());
    +    }
    +}

    Receiving html element click in component

    import { Behaviour, EventList, serializable, serializeable } from "@needle-tools/engine";
    +
    +export class HTMLButtonClick extends Behaviour {
    +
    +    /** Enter a button query (e.g. button.some-button if you're interested in a button with the class 'some-button') 
    +     * Or you can also use an id (e.g. #some-button if you're interested in a button with the id 'some-button')
    +     * Or you can also use a tag (e.g. button if you're interested in any button
    +    */
    +    @serializeable()
    +    htmlSelector: string = "button.some-button";
    +    
    +    /** This is the event to be invoked when the html element is clicked. In Unity or Blender you can assign methods to be called in the Editor */
    +    @serializable(EventList)
    +    onClick: EventList = new EventList();
    +
    +    private element? : HTMLButtonElement;
    +
    +    onEnable() {
    +        // Get the element from the DOM
    +        this.element = document.querySelector(this.htmlSelector) as HTMLButtonElement;
    +        if (this.element) {
    +            this.element.addEventListener('click', this.onClicked);
    +        }
    +        else console.warn(\`Could not find element with selector \\"\${this.htmlSelector}\\"\`);
    +    }
    +
    +    onDisable() {
    +        if (this.element) {
    +            this.element.removeEventListener('click', this.onClicked);
    +        }
    +    }
    +
    +    private onClicked = () => {
    +        this.onClick.invoke();
    +    }
    +}

    Disable environment light

    import { Behaviour } from "@needle-tools/engine";
    +import { Texture } from "three";
    +
    +export class DisableEnvironmentLight extends Behaviour {
    +
    +   private _previousEnvironmentTexture: Texture | null = null;
    +
    +   onEnable(): void {
    +       this._previousEnvironmentTexture = this.context.scene.environment;
    +       this.context.scene.environment = null;
    +   }
    +
    +   onDisable(): void {
    +       this.context.scene.environment = this._previousEnvironmentTexture;
    +   }
    +}

    Use mediapipe package to control the 3D scene with hands

    Make sure to install the mediapipe package. Visit the github link below to see the complete project setup.
    Try it live here - requires a webcam/camera

    import { FilesetResolver, HandLandmarker, HandLandmarkerResult, NormalizedLandmark } from "@mediapipe/tasks-vision";
    +import { Behaviour, Mathf, serializable, showBalloonMessage } from "@needle-tools/engine";
    +import { ParticleSphere } from "./ParticleSphere";
    +
    +export class MediapipeHands extends Behaviour {
    +
    +    @serializable(ParticleSphere)
    +    spheres: ParticleSphere[] = [];
    +
    +    private _video!: HTMLVideoElement;
    +    private _handLandmarker!: HandLandmarker;
    +
    +    async awake() {
    +        showBalloonMessage("Initializing mediapipe...")
    +
    +        const vision = await FilesetResolver.forVisionTasks(
    +            // path/to/wasm/root
    +            "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm"
    +        );
    +        this._handLandmarker = await HandLandmarker.createFromOptions(
    +            vision,
    +            {
    +                baseOptions: {
    +                    modelAssetPath: "https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/latest/hand_landmarker.task",
    +                    delegate: "GPU"
    +                },
    +                numHands: 2
    +            });
    +        //@ts-ignore
    +        await this._handLandmarker.setOptions({ runningMode: "VIDEO" });
    +
    +        this._video = document.createElement("video");
    +        this._video.setAttribute("style", "max-width: 30vw; height: auto;");
    +        console.log(this._video);
    +        this._video.autoplay = true;
    +        this._video.playsInline = true;
    +        this.context.domElement.appendChild(this._video);
    +        this.startWebcam(this._video);
    +    }
    +
    +    private _lastVideoTime: number = 0;
    +
    +    update(): void {
    +        if (!this._video || !this._handLandmarker) return;
    +        const video = this._video;
    +        if (video.currentTime !== this._lastVideoTime) {
    +            let startTimeMs = performance.now();
    +            showBalloonMessage("<strong>Control the spheres with one or two hands</strong>!<br/><br/>Sample scene by <a href='https://twitter.com/llllkatjallll/status/1659280435023605773'>Katja Rempel</a>")
    +            const detections = this._handLandmarker.detectForVideo(video, startTimeMs);
    +            this.processResults(detections);
    +            this._lastVideoTime = video.currentTime;
    +        }
    +
    +    }
    +
    +    private processResults(results: HandLandmarkerResult) {
    +        const hand1 = results.landmarks[0];
    +        // check if we have even one hand
    +        if (!hand1) return;
    +
    +        if (hand1.length >= 4 && this.spheres[0]) {
    +            const pos = hand1[4];
    +            this.processLandmark(this.spheres[0], pos);
    +        }
    +
    +        // if we have a second sphere:
    +        if (this.spheres.length >= 2) {
    +            const hand2 = results.landmarks[1];
    +            if (!hand2) {
    +                const pos = hand1[8];
    +                this.processLandmark(this.spheres[1], pos);
    +            }
    +            else {
    +                const pos = hand2[4];
    +                this.processLandmark(this.spheres[1], pos);
    +            }
    +        }
    +    }
    +
    +    private processLandmark(sphere: ParticleSphere, pos: NormalizedLandmark) {
    +        const px = Mathf.remap(pos.x, 0, 1, -6, 6);
    +        const py = Mathf.remap(pos.y, 0, 1, 6, -6);
    +        sphere.setTarget(px, py, 0);
    +    }
    +
    +    private async startWebcam(video: HTMLVideoElement) {
    +        const constraints = { video: true, audio: false };
    +        const stream = await navigator.mediaDevices.getUserMedia(constraints);
    +        video.srcObject = stream;
    +    }
    +}

    Change Color On Collision

    import { Behaviour, Collision, Renderer } from "@needle-tools/engine";
    +import{ Color } from "three";
    +
    +export class ChangeColorOnCollision extends Behaviour {
    +
    +    private renderer: Renderer | null = null;
    +    private collisionCount: number = 0;
    +
    +    private _startColor? : Color[];
    +
    +    start() {
    +        this.renderer = this.gameObject.getComponent(Renderer);
    +        if (!this.renderer) return;
    +        if(!this._startColor) this._startColor = [];
    +        for (let i = 0; i < this.renderer.sharedMaterials.length; i++) {
    +            this.renderer.sharedMaterials[i] = this.renderer.sharedMaterials[i].clone();
    +            this._startColor[i] = this.renderer.sharedMaterials[i]["color"].clone();
    +        }
    +    }
    +
    +    onCollisionEnter(_col: Collision) {
    +        if (!this.renderer) return;
    +        this.collisionCount += 1;
    +        for (let i = 0; i < this.renderer.sharedMaterials.length; i++) {
    +            this.renderer.sharedMaterials[i]["color"].setRGB(Math.random(), Math.random(), Math.random());
    +        }
    +    }
    +
    +    onCollisionExit(_col: Collision) {
    +        if (!this.renderer || !this._startColor) return;
    +        this.collisionCount -= 1;
    +        if (this.collisionCount === 0) {
    +            for (let i = 0; i < this.renderer.sharedMaterials.length; i++) {
    +                this.renderer.sharedMaterials[i]["color"].copy(this._startColor[i])
    +                // .setRGB(.1, .1, .1);
    +            }
    +        }
    +    }
    +
    +    // more events:
    +    // onCollisionStay(_col: Collision)
    +    // onCollisionExit(_col: Collision)
    +}

    Physics Trigger Relay

    Invoke events using an objects physics trigger methods

    export class PhysicsTrigger extends Behaviour {
    +
    +    @serializeable(GameObject)
    +    triggerObjects?:GameObject[];
    +
    +    @serializeable(EventList)
    +    onEnter?: EventList;
    +
    +    @serializeable(EventList)
    +    onStay?: EventList;
    +
    +    @serializeable(EventList)
    +    onExit?: EventList;
    +
    +    onTriggerEnter(col: Collider) {
    +        if(this.triggerObjects && this.triggerObjects.length > 0 && !this.triggerObjects?.includes(col.gameObject)) return;
    +        this.onEnter?.invoke();
    +    }
    +
    +    onTriggerStay(col: Collider) {
    +        if(this.triggerObjects && this.triggerObjects.length > 0 && !this.triggerObjects?.includes(col.gameObject)) return;
    +        this.onStay?.invoke();
    +    }
    +
    +    onTriggerExit(col: Collider) {
    +        if(this.triggerObjects && this.triggerObjects.length > 0 && !this.triggerObjects?.includes(col.gameObject)) return;
    +        this.onExit?.invoke();
    +    }
    +}

    Auto Reset

    Reset an object's position automatically when it's leaving a physics trigger

    import { Behaviour, Collider, GameObject, Rigidbody, serializeable } from "@needle-tools/engine";
    +import { Vector3 } from "three";
    +
    +export class StartPosition extends Behaviour {
    +
    +    //@nonSerialized
    +    startPosition?: Vector3;
    +
    +    start() {
    +        this.updateStartPosition();
    +    }
    +
    +    updateStartPosition(){
    +        this.startPosition = this.gameObject.position.clone();
    +    }
    +
    +    resetToStart() {
    +        if (!this.startPosition) return;
    +        const rb = GameObject.getComponent(this.gameObject, Rigidbody);
    +        rb?.teleport(this.startPosition);
    +    }
    +}
    +
    +/** Reset to start position when object is exiting the collider */
    +export class AutoReset extends StartPosition {
    +
    +    @serializeable(Collider)
    +    worldCollider?: Collider;
    +
    +    start(){
    +        super.start();
    +        if(!this.worldCollider) console.warn("Missing collider to reset", this);
    +    }
    +    
    +    onTriggerExit(col) {
    +        if(col === this.worldCollider){
    +            this.resetToStart();
    +        }
    +    }
    +}

    Play Audio On Collision

    import { AudioSource, Behaviour, serializeable } from "@needle-tools/engine";
    +
    +export class PlayAudioOnCollision extends Behaviour {
    +    @serializeable(AudioSource)
    +    audioSource?: AudioSource;
    +
    +    onCollisionEnter() {
    +        this.audioSource?.play();
    +    }
    +}

    Set Random Color

    Randomize the color of an object on start. Note that the materials are cloned in the start method

    import { Behaviour, serializeable, Renderer } from "@needle-tools/engine";
    +import { Color } from "three";
    +
    +export class RandomColor extends Behaviour {
    +
    +    @serializeable()
    +    applyOnStart: boolean = true;
    +
    +    start() {
    +        if (this.applyOnStart)
    +            this.applyRandomColor();
    +
    +        // if materials are not cloned and we change the color they might also change on other objects
    +        const cloneMaterials = true;
    +        if (cloneMaterials) {
    +            const renderer = this.gameObject.getComponent(Renderer);
    +            if (!renderer) {
    +                return;
    +            }
    +            for (let i = 0; i < renderer.sharedMaterials.length; i++) {
    +                renderer.sharedMaterials[i] = renderer.sharedMaterials[i].clone();
    +            }
    +        }
    +    }
    +
    +    applyRandomColor() {
    +        const renderer = this.gameObject.getComponent(Renderer);
    +        if (!renderer) {
    +            console.warn("Can not change color: No renderer on " + this.name);
    +            return;
    +        }
    +        for (let i = 0; i < renderer.sharedMaterials.length; i++) {
    +            renderer.sharedMaterials[i].color = new Color(Math.random(), Math.random(), Math.random());
    +        }
    +    }
    +}

    Spawn Objects Over Time

    import { Behaviour, GameObject, LogType, serializeable, showBalloonMessage, WaitForSeconds } from "@needle-tools/engine";
    +
    +export class TimedSpawn extends Behaviour {
    +    @serializeable(GameObject)
    +    object?: GameObject;
    +
    +    interval: number = 1000;
    +    max: number = 100;
    +
    +    private spawned: number = 0;
    +
    +    awake() {
    +        if (!this.object) {
    +            console.warn("TimedSpawn: no object to spawn");
    +            showBalloonMessage("TimedSpawn: no object to spawn", LogType.Warn);
    +            return;
    +        }
    +        GameObject.setActive(this.object, false);
    +        this.startCoroutine(this.spawn())
    +    }
    +
    +    *spawn() {
    +        if (!this.object) return;
    +        while (this.spawned < this.max) {
    +            const instance = GameObject.instantiate(this.object);
    +            GameObject.setActive(instance!, true);
    +            this.spawned += 1;
    +            yield WaitForSeconds(this.interval / 1000);
    +        }
    +    }
    +}
    `,50))])}const F=l(d,[["render",C],["__file","scripting-examples.html.vue"]]),c=JSON.parse('{"path":"/scripting-examples.html","title":"Scripting Examples","lang":"en-US","frontmatter":{"title":"Scripting Examples","description":"A collection of useful script snippets and examples.","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/scripting examples.png"}],["meta",{"name":"og:description","content":"A collection of useful script snippets and examples."}]]},"headers":[{"level":2,"title":"Basic component","slug":"basic-component","link":"#basic-component","children":[]},{"level":2,"title":"Reference an Object from Unity","slug":"reference-an-object-from-unity","link":"#reference-an-object-from-unity","children":[]},{"level":2,"title":"Reference and load an asset from Unity (Prefab or SceneAsset)","slug":"reference-and-load-an-asset-from-unity-prefab-or-sceneasset","link":"#reference-and-load-an-asset-from-unity-prefab-or-sceneasset","children":[]},{"level":2,"title":"Reference and load scenes from Unity","slug":"reference-and-load-scenes-from-unity","link":"#reference-and-load-scenes-from-unity","children":[]},{"level":2,"title":"Receive Clicks on Objects","slug":"receive-clicks-on-objects","link":"#receive-clicks-on-objects","children":[]},{"level":2,"title":"Networking Clicks on Objects","slug":"networking-clicks-on-objects","link":"#networking-clicks-on-objects","children":[{"level":3,"title":"Play Animation on click","slug":"play-animation-on-click","link":"#play-animation-on-click","children":[]}]},{"level":2,"title":"Reference an Animation Clip","slug":"reference-an-animation-clip","link":"#reference-an-animation-clip","children":[]},{"level":2,"title":"Create and invoke a UnityEvent","slug":"create-and-invoke-a-unityevent","link":"#create-and-invoke-a-unityevent","children":[{"level":3,"title":"Declare a custom event type","slug":"declare-a-custom-event-type","link":"#declare-a-custom-event-type","children":[]}]},{"level":2,"title":"Use nested objects and serialization","slug":"use-nested-objects-and-serialization","link":"#use-nested-objects-and-serialization","children":[]},{"level":2,"title":"Use Web APIs","slug":"use-web-apis","link":"#use-web-apis","children":[{"level":3,"title":"Display current location","slug":"display-current-location","link":"#display-current-location","children":[]},{"level":3,"title":"Display current time using a Coroutine","slug":"display-current-time-using-a-coroutine","link":"#display-current-time-using-a-coroutine","children":[]}]},{"level":2,"title":"Change custom shader property","slug":"change-custom-shader-property","link":"#change-custom-shader-property","children":[]},{"level":2,"title":"Switching src attribute","slug":"switching-src-attribute","link":"#switching-src-attribute","children":[]},{"level":2,"title":"Adding new postprocessing effects","slug":"adding-new-postprocessing-effects","link":"#adding-new-postprocessing-effects","children":[]},{"level":2,"title":"Custom ParticleSystem Behaviour","slug":"custom-particlesystem-behaviour","link":"#custom-particlesystem-behaviour","children":[]},{"level":2,"title":"Custom 2D Audio Component","slug":"custom-2d-audio-component","link":"#custom-2d-audio-component","children":[]},{"level":2,"title":"Arbitrary external files","slug":"arbitrary-external-files","link":"#arbitrary-external-files","children":[]},{"level":2,"title":"Receiving html element click in component","slug":"receiving-html-element-click-in-component","link":"#receiving-html-element-click-in-component","children":[]},{"level":2,"title":"Disable environment light","slug":"disable-environment-light","link":"#disable-environment-light","children":[]},{"level":2,"title":"Use mediapipe package to control the 3D scene with hands","slug":"use-mediapipe-package-to-control-the-3d-scene-with-hands","link":"#use-mediapipe-package-to-control-the-3d-scene-with-hands","children":[]},{"level":2,"title":"Change Color On Collision","slug":"change-color-on-collision","link":"#change-color-on-collision","children":[]},{"level":2,"title":"Physics Trigger Relay","slug":"physics-trigger-relay","link":"#physics-trigger-relay","children":[]},{"level":2,"title":"Auto Reset","slug":"auto-reset","link":"#auto-reset","children":[]},{"level":2,"title":"Play Audio On Collision","slug":"play-audio-on-collision","link":"#play-audio-on-collision","children":[]},{"level":2,"title":"Set Random Color","slug":"set-random-color","link":"#set-random-color","children":[]},{"level":2,"title":"Spawn Objects Over Time","slug":"spawn-objects-over-time","link":"#spawn-objects-over-time","children":[]}],"git":{"updatedTime":1726606065000},"filePathRelative":"scripting-examples.md"}');export{F as comp,c as data}; diff --git a/assets/scripting.html-UnvL8K8f.js b/assets/scripting.html-UnvL8K8f.js new file mode 100644 index 000000000..efacc0eb7 --- /dev/null +++ b/assets/scripting.html-UnvL8K8f.js @@ -0,0 +1,166 @@ +import{_ as h,r as k,o as p,c as o,a as t,b as a,w as n,d as s,e as l}from"./app-CRZRGfEE.js";const r={},d={class:"hint-container details"};function c(g,i){const e=k("RouteLink");return p(),o("div",null,[i[35]||(i[35]=t("p",null,"If you are new to scripting we recommend reading the following guides first:",-1)),t("ul",null,[t("li",null,[a(e,{to:"/getting-started/typescript-essentials.html"},{default:n(()=>i[0]||(i[0]=[s("Typescript Essentials")])),_:1})]),t("li",null,[a(e,{to:"/getting-started/for-unity-developers.html"},{default:n(()=>i[1]||(i[1]=[s("Needle Engine for Unity Developers")])),_:1})])]),i[36]||(i[36]=t("p",null,[s("If you know what you're doing, feel free to jump right into the "),t("a",{href:"https://engine.needle.tools/docs/api/latest",target:"_blank",rel:"noopener noreferrer"},"Needle Engine API documentation"),s(".")],-1)),i[37]||(i[37]=t("hr",null,null,-1)),i[38]||(i[38]=t("p",null,[s("Runtime code for Needle Engine is written in "),t("a",{href:"https://typescriptlang.org",target:"_blank",rel:"noopener noreferrer"},"TypeScript"),s(" (recommended) or "),t("a",{href:"https://javascript.info/",target:"_blank",rel:"noopener noreferrer"},"JavaScript"),s(". We automatically generate C# stub components out of that, which you can add to GameObjects in the editor. The C# components and their data are recreated by the runtime as JavaScript components with the same data and attached to three.js objects.")],-1)),t("p",null,[i[3]||(i[3]=s("Both custom components as well as built-in Unity components can be mapped to JavaScript components in this way. For example, mappings for many built-in components related to animation, rendering or physics are already ")),a(e,{to:"/component-reference.html#unity-components"},{default:n(()=>i[2]||(i[2]=[s("included in Needle Engine")])),_:1}),i[4]||(i[4]=s("."))]),i[39]||(i[39]=l('

    If you want to code-along with the following examples without having to install anything you just click the following link:


    Our web runtime engine adopts a component model similar to Unity and thus provides a lot of functionality that will feel familiar. Components attached to three's Object3D objects have lifecycle methods like awake, start, onEnable, onDisable, update and lateUpdate that you can implement. You can also use Coroutines.


    When you don't need to write code

    Often, interactive scenes can be realized using Events in Unity and calling methods on built-in components. A typical example is playing an animation on button click - you create a button, add a Click event in the inspector, and have that call Animator.SetTrigger or similar to play a specific animation.

    Needle Engine translates Unity Events into JavaScript method calls, which makes this a very fast and flexible workflow - set up your events as usual and when they're called they'll work the same as in Unity.

    image
    An example of a Button Click Event that is working out-of-the-box in Needle Engine โ€” no code needed.

    Creating a new component

    Scripts are written in TypeScript (recommended) or JavaScript.
    There are two ways to add custom scripts to your project:

    ',11)),t("ul",null,[i[16]||(i[16]=t("li",null,[t("p",null,[s("Simply add a file with an "),t("code",null,".ts"),s(" or "),t("code",null,".js"),s(" extension inside "),t("code",null,"src/scripts/"),s(" in your generated project directory, for example "),t("code",null,"src/scripts/MyFirstScript.ts")])],-1)),t("li",null,[t("p",null,[i[6]||(i[6]=s("Unity specific:")),i[7]||(i[7]=t("br",null,null,-1)),i[8]||(i[8]=s(" Organize your code into NPM Definition Files (npm packages). These help you to modularize and re-use code between projects and if you are familiar with web development they are in fact regular npm packages that are installed locally.")),i[9]||(i[9]=t("br",null,null,-1)),i[10]||(i[10]=s(" In Unity you can create NpmDef files via ")),i[11]||(i[11]=t("code",null,"Create > NPM Definition",-1)),i[12]||(i[12]=s(" and then add TypeScript files by right-clicking an NpmDef file and selecting ")),i[13]||(i[13]=t("code",null,"Create > TypeScript",-1)),i[14]||(i[14]=s(". Please see ")),a(e,{to:"/project-structure.html#npm-definition-files"},{default:n(()=>i[5]||(i[5]=[s("this chapter")])),_:1}),i[15]||(i[15]=s(" for more information."))])])]),i[40]||(i[40]=t("p",null,[s("In both approaches, source directories are watched for changes and C# stub components or Blender panels are regenerated whenever a change is detected."),t("br"),s(" Changes to the source files also result in a hot reload of the running website โ€“ you don't have to wait for Unity to recompile the C# components. This makes iterating on code pretty much instant.")],-1)),i[41]||(i[41]=t("p",null,[s("You can even have multiple component types inside one file (e.g. you can declare "),t("code",null,"export class MyComponent1"),s(" and "),t("code",null,"export class MyOtherComponent"),s(" in the same Typescript file).")],-1)),t("p",null,[i[18]||(i[18]=s("If you are new to writing Javascript or Typescript we recommend reading the ")),a(e,{to:"/getting-started/typescript-essentials.html"},{default:n(()=>i[17]||(i[17]=[s("Typescript Essentials Guide")])),_:1}),i[19]||(i[19]=s(" guide first before continuing with this guide."))]),i[42]||(i[42]=l(`
    Example: Creating a Component that rotates an object
    • Create a component that rotates an object
      Create src/scripts/Rotate.ts and add the following code:
    import { Behaviour, serializable } from "@needle-tools/engine";
    +
    +export class Rotate extends Behaviour
    +{
    +    @serializable()
    +    speed : number = 1;
    +
    +    start(){
    +        // logging this is useful for debugging in the browser. 
    +        // You can open the developer console (F12) to see what data your component contains
    +        console.log(this);
    +    }
    +
    +    // update will be called every frame
    +    update(){
    +        this.gameObject.rotateY(this.context.time.deltaTime * this.speed);
    +    }
    +}

    Now inside Unity a new script called Rotate.cs will be automatically generated. Add the new Unity component to a Cube and save the scene.
    The cube is now rotating inside the browser.
    Open the chrome developer console by F12 to inspect the log from the Rotate.start method. This is a helpful practice to learn and debug what fields are exported and currently assigned. In general all public and serializable fields and all public properties are exported.

    Now add a new field public float speed = 5 to your Unity component and save it. The Rotate component inspector now shows a speed field that you can edit. Save the scene (or click the Build button) and note that the javascript component now has the exported speed value assigned.

    `,1)),t("details",d,[i[23]||(i[23]=t("summary",null,"Create component with a custom function",-1)),t("p",null,[i[21]||(i[21]=s("Refer to the ")),a(e,{to:"/getting-started/typescript-essentials.html"},{default:n(()=>i[20]||(i[20]=[s("Typescript Essentials Guide")])),_:1}),i[22]||(i[22]=s(" to learn more about the syntax and language."))]),i[24]||(i[24]=l(`
    import { Behaviour } from "@needle-tools/engine";
    +
    +export class PrintNumberComponent extends Behaviour
    +{
    +    start(){
    +      this.printNumber(42);
    +    }
    +    
    +    private printNumber(myNumber : number){
    +        console.log("My Number is: " + myNumber);
    +    }
    +}
    `,1))]),i[43]||(i[43]=l(`
    Version Control & Unity

    While generated C# components use the type name to produce stable GUIDs, we recommend checking in generated components in version control as a good practice.

    Component architecture

    Components are added to three.js Object3Ds. This is similar to how Components in Unity are added to GameObjects. Therefore when we want to access a three.js Object3D, we can access it as this.gameObject which returns the Object3D that the component is attached to.

    Note: Setting visible to false on a Object3D will act like SetActive(false) in Unity - meaning it will also disable all the current components on this object and its children. Update events for inactive components are not being called until visible is set to true again. If you want to hide an object without affecting components you can just disable the Needle Engine Renderer component.

    Lifecycle methods

    Note that lifecycle methods are only being called when they are declared. So only declare update lifecycle methods when they are actually necessary, otherwise it may hurt performance if you have many components with update loops that do nothing.

    Method nameDescription
    awake()First method being called when a new component is created
    onEnable()Called when a component is enabled (e.g. when enabled changes from false to true)
    onDisable()Called when a component is disabled (e.g. when enabled changes from true to false)
    onDestroy()called when the Object3D or component is being destroyed
    start()Called on the start of the first frame after the component was created
    earlyUpdate()First update event
    update()Default update event
    lateUpdate()Called after update
    onBeforeRender()Last update event before render call
    onAfterRender()Called after render event

    Physic event methods

    Method nameDescription
    onCollisionEnter(col : Collision)
    onCollisionStay(col : Collision)
    onCollisionExit(col : Collision)
    onTriggerEnter(col : Collision)
    onTriggerStay(col : Collision)
    onTriggerExit(col : Collision)

    Input event methods

    Method nameDescription
    onPointerEnter(args : PointerEventData)Called when a cursor starts to hover over an object (or any of it's children)
    onPointerMove(args : PointerEventData)Called when a cursor moves over an object (or any of it's children)
    onPointerExit(args : PointerEventData)Called when a cursor exists (stops hovering) an object
    onPointerDown(args : PointerEventData)Called when a cursor is pressed over an object
    onPointerUp(args : PointerEventData)Called when a cursor is released over an object
    onPointerClick(args : PointerEventData)Called when a cursor is clicked over an object

    XR event methods

    requires Needle Engine >= 3.32.0

    Method nameDescription
    supportsXR(mode: XRSessionMode)Optionally implement if you only want to receive XR callbacks for specific XR modes like immersive-vr or immersive-ar. Return true to notify the system that you want callbacks for the passed in mode
    onBeforeXR(mode: XRSessionMode, init: XRSessionInit)Called right before a XRSession is requested and can be used to modify the XRSessionInit object
    onEnterXR(args: NeedleXREventArgs)Callback when this component joins a xr session (or becomes active in a running XR session)
    onUpdateXR(args: NeedleXREventArgs)Callback when a xr session updates (while it is still active in XR session)
    onLeaveXR(args: NeedleXREventArgs)allback when this component exists a xr session (or when it becomes inactive in a running XR session)
    onControllerAdded(args: NeedleXRControllerEventArgs)Callback when a controller is connected/added while in a XR session OR when the component joins a running XR session that has already connected controllers OR when the component becomes active during a running XR session that has already connected controllers
    onControllerRemoved(args: NeedleXRControllerEventArgs)callback when a controller is removed while in a XR session OR when the component becomes inactive during a running XR session

    Additional XR events

    Method nameDescription
    window.addEventListener("needle-xrsession-start")CustomEvent that is invoked when a XRSession starts. details contains the NeedleXRSession
    window.addEventListener("needle-xrsession-end")CustomEvent that is invoked when a XRSession starts. details contains the NeedleXRSession
    onXRSessionStart(args: { session:NeedleXRSession } )global event hook. To unsubscribe use offXRSessionStart

    Coroutines

    Coroutines can be declared using the JavaScript Generator Syntax.
    To start a coroutine, call this.startCoroutine(this.myRoutineName());

    Example

    import { Behaviour, FrameEvent } from "@needle-tools/engine";
    +
    +export class Rotate extends Behaviour {
    +
    +    start() {
    +        // the second argument is optional and allows you to specifiy 
    +        // when it should be called in the current frame loop
    +        // coroutine events are called after regular component events of the same name
    +        // for example: Update coroutine events are called after component.update() functions
    +        this.startCoroutine(this.rotate(), FrameEvent.Update);
    +    }
    +
    +    // this method is called every frame until the component is disabled
    +    *rotate() {
    +        // keep looping forever
    +        while (true) {
    +            yield;
    +        }
    +    }
    +}

    To stop a coroutine, either exit the routine by returning from it, or cache the return value of startCoroutine and call this.stopCoroutine(<...>). All Coroutines are stopped at onDisable / when disabling a component.

    Special Lifecycle hooks

    Needle Engine also exposes a few lifecycle hooks that you can use to hook into the update loop without having to write a full component.
    Those hooks can be inserted at any point in your web application (for example in toplevel scope or in a svelte component)

    Method nameDescription
    onInitialized(cb, options)Called when a new context is initialized (before the first frame)
    onClear(cb, options)Register a callback before the engine context is cleared
    onDestroy(cb, options)Register a callback in the engine before the context is destroyed
    onStart(cb, options)Called directly after components start at the beginning of a frame
    onUpdate(cb, options)Called directly after components update
    onBeforeRender(cb, options)called before calling render
    onAfterRender(cb, options)called before calling render

    For example (See example on stackblitz)

    // this can be put into e.g. main.ts or a svelte component (similar to onMount)
    +import { Context, onUpdate, onBeforeRender, onAfterRender } from "@needle-tools/engine"
    +onUpdate((ctx: Context) => {
    +    // do something... e.g. access the scene via ctx.scene
    +    console.log("UPDATE", ctx.time.frame);
    +});
    +
    +onBeforeRender((ctx: Context) => {
    +    // this event is only called once because of the { once: true } argument
    +    console.log("ON BEFORE RENDER", ctx.time.frame);
    +}, { once: true } );
    +
    +// Every event hook returns a method to unsubscribe from the event
    +const unsubscribe = onAfterRender((ctx: Context) => {
    +    console.log("ON AFTER RENDER", ctx.time.frame);
    +});
    +// Unsubscribe from the event at any time
    +setTimeout(()=> unsubscribe(), 1000);

    Finding, adding and removing components

    To access other components, use the static methods on GameObject or this.gameObject methods. For example, to access a Renderer component in the parent use GameObject.getComponentInParent(this.gameObject, Renderer) or this.gameObject.getComponentInParent(Renderer).

    Example:

    import { Behaviour, GameObject, Renderer } from "@needle-tools/engine";
    +
    +export class MyComponent extends Behaviour {
    +
    +    start() {
    +        const renderer = GameObject.getComponentInParent(this.gameObject, Renderer);
    +        console.log(renderer);
    +    }
    +}

    Some of the available methods:

    Method
    GameObject.instantiate(Object3D, InstantiateOptions)creates a new instance of this object including new instances of all its components
    GameObject.destroy(Object3D | Component)destroy a component or Object3D (and its components)
    GameObject.addNewComponent(Object3D, Type)adds (and creates) a new component for a type to the provided object. Note that awake and onEnable is already called when the component is returned
    GameObject.addComponent(Object3D, Component)moves a component instance to the provided object. It is useful if you already have an instance e.g. when you create a component with e.g. new MyComponent() and then attach it to a object
    GameObject.removeComponent(Component)removes a component from a gameObject
    GameObject.getComponent(Object3D, Type)returns the first component matching a type on the provided object.
    GameObject.getComponents(Object3D, Type)returns all components matching a type on the provided object.
    GameObject.getComponentInChildrensame as getComponent but also searches in child objects.
    GameObject.getComponentsInChildrensame as getComponents but also searches in child objects.
    GameObject.getComponentInParentsame as getComponent but also searches in parent objects.
    GameObject.getComponentsInParentsame as getComponents but also searches in parent objects.
    GameObject.findObjectOfTypesearches the whole scene for a type.
    GameObject.findObjectsOfTypesearches the whole scene for all matching types.

    Three.js and the HTML DOM

    The context refers to the runtime inside a web component.
    The three.js scene lives inside a custom HTML component called <needle-engine> (see the index.html in your project). You can access the <needle-engine> web component using this.context.domElement.

    This architecture allows for potentially having multiple needle WebGL scenes on the same webpage, that can either run on their own or communicate between each other as parts of your webpage.

    Access the scene

    To access the current scene from a component you use this.scene which is equivalent to this.context.scene, this gives you the root three.js scene object.

    To traverse the hierarchy from a component you can either iterate over the children of an object
    with a for loop:

    for(let i = 0; i < this.gameObject.children; i++) 
    +    console.log(this.gameObject.children[i]);

    or you can iterate using the foreach equivalent:

    for(const child of this.gameObject.children) {
    +    console.log(child);
    +}

    You can also use three.js specific methods to quickly iterate all objects recursively using the traverse method:

    import { Object3D } from "three";
    +this.gameObject.traverse((obj: Object3D) => console.log(obj));

    or to just traverse visible objects use traverseVisible instead.

    Another option that is quite useful when you just want to iterate objects being renderable you can query all renderer components and iterate over them like so:

    import { Renderer } from "@needle-tools/engine";
    +for(const renderer of this.gameObject.getComponentsInChildren(Renderer))
    +    console.log(renderer);

    For more information about getting components see the next section.

    Time

    Use this.context.time to get access to time data:

    • this.context.time.time is the time since the application started running
    • this.context.time.deltaTime is the time that has passed since the last frame
    • this.context.time.frameCount is the number of frames that have passed since the application started
    • this.context.time.realtimeSinceStartup is the unscaled time since the application has started running

    It is also possible to use this.context.time.timeScale to deliberately slow down time for e.g. slow motion effects.

    Input

    Receive input data for the object the component is on:

    import { Behaviour } from "@needle-tools/engine";
    +export class MyScript extends Behaviour
    +{
    +    onPointerDown() {
    +        console.log("POINTER DOWN on " + this.gameObject.name);
    +    }
    +}

    You can also subscribe to global events in the InputEvents enum like so:

    import { Behaviour, InputEvents, NEPointerEvent } from "@needle-tools/engine";
    +
    +export class MyScript extends Behaviour
    +{
    +    onEnable() {
    +        this.context.input.addEventListener(InputEvents.PointerDown, this.inputPointerDown);
    +    }
    +
    +    onDisable() {
    +        // it is recommended to also unsubscribe from events when your component becomes inactive
    +        this.context.input.removeEventListener(InputEvents.PointerDown, this.inputPointerDown);
    +    }
    +
    +    // @nonSerialized
    +    inputPointerDown = (evt: NEPointerEvent) => { console.log("POINTER DOWN anywhere on the <needle-engine> element"); }
    +}

    Or use this.context.input if you want to poll input state every frame:

    import { Behaviour } from "@needle-tools/engine";
    +export class MyScript extends Behaviour
    +{
    +    update() {
    +        if(this.context.input.getPointerDown(0)){
    +            console.log("POINTER DOWN anywhere")
    +        }
    +    }
    +}

    If you want to handle inputs yourself you can also subscribe to all events the browser provides (there are a ton). For example to subscribe to the browsers click event you can write:

    import { Behaviour } from "@needle-tools/engine";
    +export class MyScript extends Behaviour
    +{
    +    onEnable() {
    +        window.addEventListener("click", this.windowClick);
    +    }
    +
    +    onDisable() {
    +        // unsubscribe again when the component is disabled
    +        window.removeEventListener("click", this.windowClick);
    +    }
    +
    +    windowClick = () => { console.log("CLICK anywhere on the page, not just on <needle-engine>"); }
    +}

    Note that in this case you have to handle all cases yourself. For example you may need to use different events if your user is visiting your website on desktop vs mobile vs a VR device. These cases are automatically handled by the Needle Engine input events (e.g. PointerDown is raised both for mouse down, touch down and in case of VR on controller button down).

    Physics

    Use this.context.physics.raycast() to perform a raycast and get a list of intersections. If you dont pass in any options the raycast is performed from the mouse position (or first touch position) in screenspace using the currently active mainCamera. You can also pass in a RaycastOptions object that has various settings like maxDistance, the camera to be used or the layers to be tested against.

    Use this.context.physics.raycastFromRay(your_ray) to perform a raycast using a three.js ray

    Note that the calls above are by default raycasting against visible scene objects. That is different to Unity where you always need colliders to hit objects. The default three.js solution has both pros and cons where one major con is that it can perform quite slow depending on your scene geometry. It may be especially slow when raycasting against skinned meshes. It is therefor recommended to usually set objects with SkinnedMeshRenderers in Unity to the Ignore Raycast layer which will then be ignored by default by Needle Engine as well.

    Another option is to use the physics raycast methods which will only return hits with colliders in the scene.

    const hit = this.context.physics.engine?.raycast();

    Here is a editable example for physics raycast

    Networking

    `,69)),t("p",null,[i[26]||(i[26]=s("Networking methods can be accessed via ")),i[27]||(i[27]=t("code",null,"this.context.connection",-1)),i[28]||(i[28]=s(". Please refer to the ")),a(e,{to:"/networking.html"},{default:n(()=>i[25]||(i[25]=[s("networking docs")])),_:1}),i[29]||(i[29]=s(" for further information."))]),i[44]||(i[44]=l(`

    Accessing Needle Engine and components from anywhere

    It is possible to access all the functionality described above using regular JavaScript code that is not inside components and lives somewhere else. All the components and functionality of the needle runtime is accessible via the global Needle namespace (you can write console.log(Needle) to get an overview)

    You can find components using Needle.findObjectOfType(Needle.AudioSource) for example. It is recommended to cache those references, as searching the whole scene repeatedly is expensive. See the list for finding adding and removing components above.

    For getting callbacks for the initial scene load see the following example:

    <needle-engine loadstart="loadingStarted" progress="loadingProgress" loadfinished="loadingFinished"></needle-engine>
    +
    +<script type="text/javascript">
    +function loadingStarted() { console.log("START") }
    +function loadingProgress() { console.log("LOADING...") }
    +function loadingFinished() { console.log("FINISHED!") }
    +</script>

    You can also subscribe to the globale NeedleEngine (sometimes also referred to as ContextRegistry) to receive a callback when a Needle Engine context has been created or to access all available contexts:

    class YourComponentType extends Behaviour {}
    +//---cut---
    +import { NeedleEngine, GameObject, Behaviour } from "@needle-tools/engine";
    +
    +NeedleEngine.addContextCreatedCallback((args) => {
    +  const context = args.context;
    +  const scene = context.scene;
    +  const myInstance = GameObject.getComponentInChildren(scene, YourComponentType);
    +});

    Another option is using the onInitialized(ctx => {}) lifecycle hook

    You can also access all available contexts via NeedleEngine.Registered which returns the internal array. (Note that this array should not be modified but can be used to iterate all active contexts to modify settings, e.g. set all contexts to context.isPaused = true)

    Below you find a list of available events on the static NeedleEngine type.
    You can subscribe to those events via NeedleEngine.registerCallback(ContextEvent.ContextCreated, (args) => {})

    ContextEvent options
    ContextEvent.ContextRegisteredCalled when the context is registered to the registry.
    ContextEvent.ContextCreationStartCalled before the first glb is loaded and can be used to initialize the physics engine. Can return a promise
    ContextEvent.ContextCreatedCalled when the context has been created before the first frame
    ContextEvent.ContextDestroyedCalled when the context has been destroyed
    ContextEvent.MissingCameraCalled when the context could not find a camera, currently only called during creation
    ContextEvent.ContextClearingCalled when the context is being cleared: all objects in the scene are being destroyed and internal state is reset
    ContextEvent.ContextClearedCalled after the context has been cleared

    Gizmos

    The static Gizmos class can be used to draw lines, shapes and text which is mostly useful for debugging.
    All gizmos function have multiple options for e.g. colors or for how long they should be displayed in the scene. Internally they are cached and re-used.

    Gizmos
    Gizmos.DrawLabelDraws a label with a background optionally. It can be attached to an object. Returns a Label handle which can be used to update the text.
    Gizmos.DrawRayTakes an origin and direction in worldspace to draw an infinite ray line
    Gizmos.DrawDirectionTakes a origin and direction to draw a direction in worldspace
    Gizmos.DrawLineTakes two vec3 worldspace points to draw a line
    Gizmos.DrawWireSphereDraws a wireframe sphere in worldspace
    Gizmos.DrawSphereDraws a solid sphere in worldspace
    Gizmos.DrawWireBoxDraws a wireframe box in worldspace
    Gizmos.DrawWireBox3Draws a wireframe box3
    Gizmos.DrawArrowDraws an arrow taking two points in worldspace

    Serialization / Components in glTF files

    To embed components and recreate components with their correct types in glTF, we also need to save non-primitive types (everything that is not a Number, Boolean or String). You can do so is adding a @serializable(<type>) decorator above your field or property.

    Example:

    import { Behaviour, serializable } from "@needle-tools/engine";
    +import { Object3D } from "three"
    +
    +export class MyClass extends Behaviour {
    +    // this will be a "Transform" field in Unity
    +    @serializable(Object3D) 
    +    myObjectReference: Object3D | null = null;
    +    
    +    // this will be a "Transform" array field in Unity
    +    // Note that the @serializable decorator contains the array content type! (Object3D and not Object3D[])
    +    @serializable(Object3D) 
    +    myObjectReferenceList: Object3D[] | null = null;
    +}

    To serialize from and to custom formats, it is possible to extend from the TypeSerializer class and create an instance. Use super() in the constructor to register supported types.

    Note: In addition to matching fields, matching properties will also be exported when they match to fields in the typescript file.

    Loading Scenes

    `,21)),t("p",null,[i[31]||(i[31]=s("Referenced Prefabs, SceneAssets and ")),i[32]||(i[32]=t("a",{href:"https://docs.unity3d.com/Packages/com.unity.addressables@latest/manual/AddressableAssetsGettingStarted.html",target:"_blank",rel:"noopener noreferrer"},[t("code",null,"AssetReferences")],-1)),i[33]||(i[33]=s(" in Unity will automatically be exported as glTF files (please refer to the ")),a(e,{to:"/export.html"},{default:n(()=>i[30]||(i[30]=[s("Export Prefabs")])),_:1}),i[34]||(i[34]=s(" documentation)."))]),i[45]||(i[45]=l(`

    These exported gltf files will be serialized as plain string URIs. To simplify loading these from TypeScript components, we added the concept of AssetReference types. They can be loaded at runtime and thus allow to defer loading parts of your app or loading external content.

    Example:

    import { Behaviour, serializable, AssetReference } from "@needle-tools/engine";
    +
    +export class MyClass extends Behaviour {
    +
    +    // if you export a prefab or scene as a reference from Unity you'll get a path to that asset
    +    // which you can de-serialize to AssetReference for convenient loading
    +    @serializable(AssetReference)
    +    myPrefab?: AssetReference;
    +    
    +    async start() {
    +      // directly instantiate
    +      const myInstance = await this.myPrefab?.instantiate();
    +
    +      // you can also just load and instantiate later
    +      // const myInstance = await this.myPrefab.loadAssetAsync();
    +      // this.gameObject.add(myInstance)
    +      // this is useful if you know that you want to load this asset only once because it will not create a copy
    +      // since \`\`instantiate()\`\` does create a copy of the asset after loading it
    +    }  
    +}

    AssetReferences are cached by URI, so if you reference the same exported glTF/Prefab in multiple components/scripts it will only be loaded once and then re-used.

    `,4))])}const C=h(r,[["render",c],["__file","scripting.html.vue"]]),F=JSON.parse(`{"path":"/scripting.html","title":"Creating and using Components","lang":"en-US","frontmatter":{"title":"Creating and using Components","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/creating and using components.png"}],["meta",{"name":"og:description","content":"---\\nIf you are new to scripting we recommend reading the following guides first:"}]],"description":"---\\nIf you are new to scripting we recommend reading the following guides first:"},"headers":[{"level":2,"title":"When you don't need to write code","slug":"when-you-don-t-need-to-write-code","link":"#when-you-don-t-need-to-write-code","children":[]},{"level":2,"title":"Creating a new component","slug":"creating-a-new-component","link":"#creating-a-new-component","children":[]},{"level":2,"title":"Component architecture","slug":"component-architecture","link":"#component-architecture","children":[{"level":3,"title":"Lifecycle methods","slug":"lifecycle-methods","link":"#lifecycle-methods","children":[]},{"level":3,"title":"Physic event methods","slug":"physic-event-methods","link":"#physic-event-methods","children":[]},{"level":3,"title":"Input event methods","slug":"input-event-methods","link":"#input-event-methods","children":[]},{"level":3,"title":"XR event methods","slug":"xr-event-methods","link":"#xr-event-methods","children":[]},{"level":3,"title":"Coroutines","slug":"coroutines","link":"#coroutines","children":[]}]},{"level":2,"title":"Special Lifecycle hooks","slug":"special-lifecycle-hooks","link":"#special-lifecycle-hooks","children":[]},{"level":2,"title":"Finding, adding and removing components","slug":"finding-adding-and-removing-components","link":"#finding-adding-and-removing-components","children":[{"level":3,"title":"Some of the available methods:","slug":"some-of-the-available-methods","link":"#some-of-the-available-methods","children":[]}]},{"level":2,"title":"Three.js and the HTML DOM","slug":"three.js-and-the-html-dom","link":"#three.js-and-the-html-dom","children":[{"level":3,"title":"Access the scene","slug":"access-the-scene","link":"#access-the-scene","children":[]},{"level":3,"title":"Time","slug":"time","link":"#time","children":[]},{"level":3,"title":"Input","slug":"input","link":"#input","children":[]},{"level":3,"title":"Physics","slug":"physics","link":"#physics","children":[]},{"level":3,"title":"Networking","slug":"networking","link":"#networking","children":[]}]},{"level":2,"title":"Accessing Needle Engine and components from anywhere","slug":"accessing-needle-engine-and-components-from-anywhere","link":"#accessing-needle-engine-and-components-from-anywhere","children":[]},{"level":2,"title":"Gizmos","slug":"gizmos","link":"#gizmos","children":[]},{"level":2,"title":"Serialization / Components in glTF files","slug":"serialization-components-in-gltf-files","link":"#serialization-components-in-gltf-files","children":[]},{"level":2,"title":"Loading Scenes","slug":"loading-scenes","link":"#loading-scenes","children":[]}],"git":{"updatedTime":1726585195000},"filePathRelative":"scripting.md"}`);export{C as comp,F as data}; diff --git a/assets/set-fallback-material-for-usdz-exporter.html-BEiyoRdx.js b/assets/set-fallback-material-for-usdz-exporter.html-BEiyoRdx.js new file mode 100644 index 000000000..f58161232 --- /dev/null +++ b/assets/set-fallback-material-for-usdz-exporter.html-BEiyoRdx.js @@ -0,0 +1,45 @@ +import{_ as t,r as n,o as l,c as h,a as i,b as k,e}from"./app-CRZRGfEE.js";const p={};function r(d,s){const a=n("contribution-header");return l(),h("div",null,[s[0]||(s[0]=i("p",null,[i("a",{href:"/docs/community/contributions"},"Overview")],-1)),k(a,{url:"https://github.com/llllkatjallll",author:"llllkatjallll",page:"/docs/community/contributions/llllkatjallll",profileImage:"https://avatars.githubusercontent.com/u/38395689?s=100&u=7ce0fef973c4819c4f07823568d6f6061abfe410&v=4",githubUrl:"https://github.com/needle-tools/needle-engine-support/discussions/184",title:"Set fallback material for USDZ exporter",gradient:"True"}),s[1]||(s[1]=e(`

    If you want to set a fallback material for an object that will be exported as USDZ (for AR-mode on iOS), you can add this script to the object, which material should be replaced.

    This is especially useful if you use custom shaders in your scene (they are visible on Desktop+WebXR, but not in AR on iOS).

    import { Behaviour, GameObject, Renderer, USDZExporter, serializable } from "@needle-tools/engine";
    +import { Material, Object3D } from "three";
    +
    +export class FallbackMaterial extends Behaviour {
    +
    +    @serializable(Material)
    +    fallbackMaterial!: Material;
    +
    +    private originalMaterial?: Material;
    +    private usdzExporter!: USDZExporter;
    +
    +    onEnable() {
    +        this.usdzExporter = GameObject.findObjectOfType(USDZExporter)!;
    +        this.subscribeToBeforeExportEvent();
    +    }
    +
    +    onDisable() {
    +        this.unsubscribeFromBeforeExportEvent();
    +    }
    +
    +    private subscribeToBeforeExportEvent() {
    +        this.usdzExporter.addEventListener("before-export", this.onBeforeExport);
    +        this.usdzExporter.addEventListener("after-export", this.onAfterExport);
    +    }
    +
    +    private unsubscribeFromBeforeExportEvent() {
    +        this.usdzExporter.removeEventListener("before-export", this.onBeforeExport);
    +        this.usdzExporter.removeEventListener("after-export", this.onAfterExport);
    +    }
    +
    +
    +    onBeforeExport = () => {
    +        console.log("onBeforeExport");
    +        const renderer = this.gameObject.getComponent(Renderer)!;
    +        this.originalMaterial = renderer.sharedMaterial;
    +        renderer.sharedMaterial = this.fallbackMaterial;
    +
    +    }
    +
    +    onAfterExport = () => {
    +        console.log("onAfterExport");
    +        const renderer = this.gameObject.getComponent(Renderer)!;
    +        renderer.sharedMaterial = this.originalMaterial;
    +    }
    +}
    `,3))])}const y=t(p,[["render",r],["__file","set-fallback-material-for-usdz-exporter.html.vue"]]),g=JSON.parse('{"path":"/community/contributions/llllkatjallll/set-fallback-material-for-usdz-exporter","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/llllkatjallll: set fallback material for usdz exporter.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{y as comp,g as data}; diff --git a/assets/showcase-bike.html-C8g9IaUw.js b/assets/showcase-bike.html-C8g9IaUw.js new file mode 100644 index 000000000..233dfe0cd --- /dev/null +++ b/assets/showcase-bike.html-C8g9IaUw.js @@ -0,0 +1 @@ +import{_ as n,r as s,o,c as a,a as e,b as l}from"./app-CRZRGfEE.js";const r={};function c(d,t){const i=s("sample");return o(),a("div",null,[t[0]||(t[0]=e("h3",{id:"live",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#live"},[e("span",null,"Live")])],-1)),l(i,{src:"https://bike.needle.tools"}),t[1]||(t[1]=e("p",null,[e("a",{href:"https://bike.needle.tools",target:"_blank",rel:"noopener noreferrer"},"Visit website")],-1))])}const m=n(r,[["render",c],["__file","showcase-bike.html.vue"]]),h=JSON.parse('{"path":"/showcase-bike.html","title":"Bike Configurator ๐Ÿšฒ","lang":"en-US","frontmatter":{"lang":"en-US","title":"Bike Configurator ๐Ÿšฒ","sidebar":false,"editLink":false,"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/bike configurator.png"}],["meta",{"name":"og:description","content":"---\\nVisit website"}]],"description":"---\\nVisit website"},"headers":[{"level":3,"title":"Live","slug":"live","link":"#live","children":[]}],"git":{"updatedTime":1669763662000},"filePathRelative":"showcase-bike.md"}');export{m as comp,h as data}; diff --git a/assets/showcase-castle.html-2qaErZDl.js b/assets/showcase-castle.html-2qaErZDl.js new file mode 100644 index 000000000..315fd5364 --- /dev/null +++ b/assets/showcase-castle.html-2qaErZDl.js @@ -0,0 +1 @@ +import{_ as a,r as n,o as r,c as i,a as t,b as s,e as l}from"./app-CRZRGfEE.js";const c={};function d(u,e){const o=n("sample");return r(),i("div",null,[e[0]||(e[0]=t("h3",{id:"live",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#live"},[t("span",null,"Live")])],-1)),s(o,{src:"https://castle.needle.tools"}),e[1]||(e[1]=l('

    Visit website

    How To Play

    Build your own castle! Drag 3D models from the various palettes onto the stage, and create your very own world. Works on Desktop, Mobile, VR, AR, all right in your browser. Interactions are currently optimized for VR; placement on screens is a bit harder but possible. Have fun, no matter which device you're on!

    Invite your friends! Click Create Room to be put into a live, multi-user space โ€“ just copy the URL, send it to a friend and they join you automatically. There's currently a max limit for "users online at the same time" - if you don't get into a room, please try later.

    Info

    This page was authored in Unity and exported to three.js using tools and technologies by ๐ŸŒต needle.

    There are a lot of open technologies involved: 3D models are in glTF format, the render engine is three.js, VR and AR are using WebXR. The networking server runs on Glitch, and audio is sent over WebRTC using PeerJS.

    ',7))])}const p=a(c,[["render",d],["__file","showcase-castle.html.vue"]]),m=JSON.parse(`{"path":"/showcase-castle.html","title":"Castle Builder ๐Ÿฐ","lang":"en-US","frontmatter":{"lang":"en-US","title":"Castle Builder ๐Ÿฐ","sidebar":false,"editLink":false,"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/castle builder.png"}],["meta",{"name":"og:description","content":"---\\nVisit website\\nBuild your own castle! Drag 3D models from the various palettes onto the stage, and create your very own world.\\nWorks on Desktop, Mobile, VR, AR, all right in your browser. Interactions are currently optimized for VR; placement on screens is a bit harder but possible. Have fun, no matter which device you're on!\\nInvite your friends! Click Create Room to be put into a live, multi-user space โ€“ just copy the URL, send it to a friend and they join you automatically.\\nThere's currently a max limit for 'users online at the same time'"}]],"description":"---\\nVisit website\\nBuild your own castle! Drag 3D models from the various palettes onto the stage, and create your very own world.\\nWorks on Desktop, Mobile, VR, AR, all right in your browser. Interactions are currently optimized for VR; placement on screens is a bit harder but possible. Have fun, no matter which device you're on!\\nInvite your friends! Click Create Room to be put into a live, multi-user space โ€“ just copy the URL, send it to a friend and they join you automatically.\\nThere's currently a max limit for 'users online at the same time'"},"headers":[{"level":3,"title":"Live","slug":"live","link":"#live","children":[]},{"level":3,"title":"How To Play","slug":"how-to-play","link":"#how-to-play","children":[]},{"level":3,"title":"Info","slug":"info","link":"#info","children":[]}],"git":{"updatedTime":1669763662000},"filePathRelative":"showcase-castle.md"}`);export{p as comp,m as data}; diff --git a/assets/showcase-mercedes-benz.html-CYMbPrd8.js b/assets/showcase-mercedes-benz.html-CYMbPrd8.js new file mode 100644 index 000000000..d6dbcc4ed --- /dev/null +++ b/assets/showcase-mercedes-benz.html-CYMbPrd8.js @@ -0,0 +1,29 @@ +import{_ as t,r as n,o as h,c as l,a as s,d as e,b as p,e as r}from"./app-CRZRGfEE.js";const o="/docs/showcase-mercedes/1_skybox.png",d="/docs/showcase-mercedes/2_paintjob_simple.jpg",k="/docs/showcase-mercedes/3_SpecularHighlights_off.jpg",c="/docs/showcase-mercedes/4_SpecularHighlights_on.jpg",g="/docs/showcase-mercedes/5_NoBackground.jpg",y="/docs/showcase-mercedes/6_MapBackground.png",m="/docs/showcase-mercedes/7_EnvShaderGraph.jpg",u="/docs/showcase-mercedes/8_Gradiant.png",w="/docs/showcase-mercedes/9_Rotator.png",C="/docs/showcase-mercedes/10_WheelsAndGrid.png",b="/docs/showcase-mercedes/11_GridShader.jpg",f="/docs/showcase-mercedes/12_WheelWithText.png",F="/docs/showcase-mercedes/13_WheelShader.jpg",E="/docs/showcase-mercedes/14_RearUI.jpg",B={};function v(x,i){const a=n("sample");return h(),l("div",null,[i[0]||(i[0]=s("h2",{id:"about",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#about"},[s("span",null,"About")])],-1)),i[1]||(i[1]=s("p",null,[e("Hello, my name is Kryลกtof and i did a research project about Needle. At "),s("a",{href:"https://www.ishowroom.cz/home/",target:"_blank",rel:"noopener noreferrer"},"our company"),e(", we wanted to determine how Needle can help us in our workflow. We have one local client which focuses on reselling luxury cars. We already delivered a mobile app and VR experience using Unity. We have around 30 unique cars ready in the engine. We plan to expand the client's website with visually pleasing digital clones with more configuration options. Needle could achieve a perfect 1:1 conversion between unity and web visuals. It would be a massive benefit to our workflow. So that's what sparked our research.")],-1)),p(a,{src:"https://engine.needle.tools/demos/mercedes-benz-demo/"}),i[2]||(i[2]=r('

    Context

    I'm not very well experienced with javascript, typescript or three.js, so my point of view is as a semi-experienced Unity developer trying out the simplest way how to create a web experience. For those who would suggest Unity WebGL, that sadly doesn't work and isn't flexible on mobile browsers. Needle is ๐Ÿ’š

    Lighting

    Our lighting model is based on reflection probes in unity. We do not need any directional or point lights, only ambient lighting.

    We're using this skybox:

    Skybox

    Which looks like this on the paint job:

    Paintjob

    Then to add a slight detail, i've added 2 directional lights with an insignificant intensity (0.04) to create specular highlights. So before it looked like this:

    Specular off

    But with the added directional lights it added a better dynamic. The effect could be deepened with higher intensity:

    Specular on

    Background

    The scene now looks like this:

    No background

    The black background isn't very pretty. So to differentiate between visual and lighting skyboxes i've added an inverse sphere which wraps the whole map.

    With background

    Regarding the gradient goes from a slight gray to a white color..

    This effect could be easily made with just a proper UV mapping and a single pixel high texture which would define the gradient.

    I've made an unlit shader in the shader graph:

    Evironemnt shader

    I've noticed a color banding issue, so i've tried to implement dithering. Frankly, it didn't help the artefacts but i bet there's a simple solution to that issue. So the upper part of the shader does sample the gradient based on the Y axis in object space. And the lower part tries to negate the color banding.

    By using shaders it's simpler to use and iterate the gradiant. By using Needle's Shadergraph markdown asset, it's even simpler! ๐ŸŒต

    Gradiant

    Car fake movement

    The scene right now is static since nothing moves. We can negate that by adding a fake feeling of motion. Let's start by adding motion to the wheels.

    With a simple component called Rotator, we define an axis and speed along it.

    Rotator

    import { Behaviour, serializable } from "@needle-tools/engine";
    +
    +export enum RotationAxis {
    +    X, Y, Z
    +}
    +
    +export class Rotator extends Behaviour {
    +    //@type RotationAxis
    +    @serializable()
    +    axis : RotationAxis = RotationAxis.X;
    +
    +    @serializable()
    +    speed : number = 1;
    +
    +    update() {
    +        const angle = this.speed * this.context.time.deltaTime;
    +        switch(this.axis) {
    +            case RotationAxis.X:
    +                this.gameObject.rotateX(angle);
    +                break;
    +            case RotationAxis.Y:
    +                this.gameObject.rotateY(angle);
    +                break;
    +            case RotationAxis.Z:
    +                this.gameObject.rotateZ(angle);
    +                break;
    +        }
    +    }
    +}

    The user now sees a car driving in deep nothingness, the color doesn't resemble anything and the experience is dull. We want to ground the model and that's done by adding a grid and then shifting it so it seems the car is moving. This is what we want to achieve:

    Motion

    The shader for the grid was comprised of two parts. A simple tiled texture of the grid that's being multipled by a circular gradient to make the edges fade off.

    Grid

    Extra elements

    This tech demo takes it's goal to showcase the car's capabilities.

    Let's start by highlighting the wheels.

    Wheel highlight

    Adding this shader to a plane will result in a dashed circle which is rotating by a defined speed. Combined with world space UI with a normal Text component this can highlight some interesting capabilities or parameters of the given product.

    Wheel shader

    After showcasing the wheels we want to finish with a broad information about the product. In this case, that would be the car's full name and perhaps some available configurations.

    Rear UI

    Wrap up

    By using the Unity's timeline we can control when the wheel dashes and text will be shown. This is complemented by the camera animation.

    Conclusion

    Needle Engine seems to be a very good candidate for us!

    There are a few features which we miss.

    That would be for example proper support for the Lit Shader Graphs. But nothing stops us to create shaders the three.js way and create simmilar shaders in Unity for our content team to tweak the materials.

    Using Needle was a blast! ๐ŸŒต

    ',48))])}const A=t(B,[["render",v],["__file","showcase-mercedes-benz.html.vue"]]),D=JSON.parse(`{"path":"/showcase-mercedes-benz.html","title":"Mercedes-Benz Showcase","lang":"en-US","frontmatter":{"lang":"en-US","title":"Mercedes-Benz Showcase","editLink":false,"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/mercedes benz showcase.png"}],["meta",{"name":"og:description","content":"---\\nHello, my name is Kryลกtof and i did a research project about Needle. At our company, we wanted to determine how Needle can help us in our workflow. We have one local client which focuses on reselling luxury cars. We already delivered a mobile app and VR experience using Unity. We have around 30 unique cars ready in the engine. We plan to expand the client's website with visually pleasing digital clones with more configuration options. Needle could achieve a perfect 1:1 conversion between unity and web visuals. It would be a massive benefit to our workflow. So that's what sparked our research.\\nI'm not very well experienced with javascript, typescript or three.js, so my point of view is as a semi-experienced Unity developer trying out the simplest way how to create a web experience. For those who would suggest Unity WebGL, that sadly doesn't work and isn't flexible on mobile browsers. Needle is ๐Ÿ’š\\nOur lighting model is based on reflection probes in unity. We do not need any directional or point lights, only ambient lighting.\\nWe're using this skybox:\\nWhich looks like this on the paint job:\\nThen to add a slight detail, i've added 2 directional lights with an insignificant intensity (0.04) to create specular highlights. So before it looked like this:\\nBut with the added directional lights it added a better dynamic. The effect could be deepened with higher intensity:\\nThe scene now looks like this:\\nThe black background isn't very pretty. So to differentiate b"}]],"description":"---\\nHello, my name is Kryลกtof and i did a research project about Needle. At our company, we wanted to determine how Needle can help us in our workflow. We have one local client which focuses on reselling luxury cars. We already delivered a mobile app and VR experience using Unity. We have around 30 unique cars ready in the engine. We plan to expand the client's website with visually pleasing digital clones with more configuration options. Needle could achieve a perfect 1:1 conversion between unity and web visuals. It would be a massive benefit to our workflow. So that's what sparked our research.\\nI'm not very well experienced with javascript, typescript or three.js, so my point of view is as a semi-experienced Unity developer trying out the simplest way how to create a web experience. For those who would suggest Unity WebGL, that sadly doesn't work and isn't flexible on mobile browsers. Needle is ๐Ÿ’š\\nOur lighting model is based on reflection probes in unity. We do not need any directional or point lights, only ambient lighting.\\nWe're using this skybox:\\nWhich looks like this on the paint job:\\nThen to add a slight detail, i've added 2 directional lights with an insignificant intensity (0.04) to create specular highlights. So before it looked like this:\\nBut with the added directional lights it added a better dynamic. The effect could be deepened with higher intensity:\\nThe scene now looks like this:\\nThe black background isn't very pretty. So to differentiate b"},"headers":[{"level":2,"title":"About","slug":"about","link":"#about","children":[]},{"level":2,"title":"Context","slug":"context","link":"#context","children":[]},{"level":2,"title":"Lighting","slug":"lighting","link":"#lighting","children":[]},{"level":2,"title":"Background","slug":"background","link":"#background","children":[]},{"level":2,"title":"Car fake movement","slug":"car-fake-movement","link":"#car-fake-movement","children":[]},{"level":2,"title":"Extra elements","slug":"extra-elements","link":"#extra-elements","children":[]},{"level":2,"title":"Wrap up","slug":"wrap-up","link":"#wrap-up","children":[]},{"level":2,"title":"Conclusion","slug":"conclusion","link":"#conclusion","children":[]}],"git":{"updatedTime":1726585195000},"filePathRelative":"showcase-mercedes-benz.md"}`);export{A as comp,D as data}; diff --git a/assets/showcase-monsterhands.html-Cjm5xxr6.js b/assets/showcase-monsterhands.html-Cjm5xxr6.js new file mode 100644 index 000000000..50575c601 --- /dev/null +++ b/assets/showcase-monsterhands.html-Cjm5xxr6.js @@ -0,0 +1 @@ +import{_ as n,r as a,o,c as r,a as e,b as l}from"./app-CRZRGfEE.js";const i={};function d(m,t){const s=a("sample");return o(),r("div",null,[t[0]||(t[0]=e("h3",{id:"live",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#live"},[e("span",null,"Live")])],-1)),l(s,{src:"https://monster-hands.needle.tools/"}),t[1]||(t[1]=e("p",null,[e("a",{href:"https://monster-hands.needle.tools/",target:"_blank",rel:"noopener noreferrer"},"Visit website")],-1))])}const h=n(i,[["render",d],["__file","showcase-monsterhands.html.vue"]]),p=JSON.parse('{"path":"/showcase-monsterhands.html","title":"Monster Hands ๐Ÿ’€","lang":"en-US","frontmatter":{"lang":"en-US","title":"Monster Hands ๐Ÿ’€","sidebar":false,"editLink":false,"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/monster hands.png"}],["meta",{"name":"og:description","content":"---\\nVisit website"}]],"description":"---\\nVisit website"},"headers":[{"level":3,"title":"Live","slug":"live","link":"#live","children":[]}],"git":{"updatedTime":1682497626000},"filePathRelative":"showcase-monsterhands.md"}');export{h as comp,p as data}; diff --git a/assets/showcase-towerdefence.html-B-3p76-5.js b/assets/showcase-towerdefence.html-B-3p76-5.js new file mode 100644 index 000000000..33bdfecae --- /dev/null +++ b/assets/showcase-towerdefence.html-B-3p76-5.js @@ -0,0 +1 @@ +import{_ as s,r as o,o as a,c as i,a as e,b as l}from"./app-CRZRGfEE.js";const r={};function d(c,t){const n=o("sample");return a(),i("div",null,[t[0]||(t[0]=e("h3",{id:"live",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#live"},[e("span",null,"Live")])],-1)),l(n,{src:"https://v6p9d9t4.ssl.hwcdn.net/html/7746989/index.html"}),t[1]||(t[1]=e("p",null,[e("a",{href:"https://willitaugment.itch.io/tumbleweed-defender",target:"_blank",rel:"noopener noreferrer"},"Visit website")],-1))])}const p=s(r,[["render",d],["__file","showcase-towerdefence.html.vue"]]),f=JSON.parse('{"path":"/showcase-towerdefence.html","title":"Tower Defense","lang":"en-US","frontmatter":{"lang":"en-US","title":"Tower Defense","sidebar":false,"editLink":false,"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/tower defense.png"}],["meta",{"name":"og:description","content":"---\\nVisit website"}]],"description":"---\\nVisit website"},"headers":[{"level":3,"title":"Live","slug":"live","link":"#live","children":[]}],"git":{"updatedTime":1684592760000},"filePathRelative":"showcase-towerdefence.md"}');export{p as comp,f as data}; diff --git a/assets/showcase-website.html-DsWtTfPo.js b/assets/showcase-website.html-DsWtTfPo.js new file mode 100644 index 000000000..1e69d4afd --- /dev/null +++ b/assets/showcase-website.html-DsWtTfPo.js @@ -0,0 +1 @@ +import{_ as n,r as l,o as a,c as i,a as e,b as o}from"./app-CRZRGfEE.js";const r={};function d(c,t){const s=l("sample");return a(),i("div",null,[t[0]||(t[0]=e("h3",{id:"live",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#live"},[e("span",null,"Live")])],-1)),o(s,{src:"https://needle.tools"}),t[1]||(t[1]=e("p",null,[e("a",{href:"https://needle.tools",target:"_blank",rel:"noopener noreferrer"},"Visit website")],-1))])}const m=n(r,[["render",d],["__file","showcase-website.html.vue"]]),h=JSON.parse('{"path":"/showcase-website.html","title":"Castle Builder ๐Ÿฐ","lang":"en-US","frontmatter":{"lang":"en-US","title":"Castle Builder ๐Ÿฐ","sidebar":false,"editLink":false,"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/castle builder.png"}],["meta",{"name":"og:description","content":"---\\nVisit website"}]],"description":"---\\nVisit website"},"headers":[{"level":3,"title":"Live","slug":"live","link":"#live","children":[]}],"git":{"updatedTime":1669763662000},"filePathRelative":"showcase-website.md"}');export{m as comp,h as data}; diff --git a/assets/showcase-zenrepublic.html-C8fRcD0r.js b/assets/showcase-zenrepublic.html-C8fRcD0r.js new file mode 100644 index 000000000..61d1d5832 --- /dev/null +++ b/assets/showcase-zenrepublic.html-C8fRcD0r.js @@ -0,0 +1 @@ +import{_ as s,r as a,o as i,c as l,a as e,b as r}from"./app-CRZRGfEE.js";const o={};function c(p,t){const n=a("sample");return i(),l("div",null,[t[0]||(t[0]=e("h3",{id:"live",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#live"},[e("span",null,"Live")])],-1)),r(n,{src:"https://zenrepublic.space/?realm=3"}),t[1]||(t[1]=e("p",null,[e("a",{href:"https://zenrepublic.space/?realm=3",target:"_blank",rel:"noopener noreferrer"},"Visit website")],-1))])}const m=s(o,[["render",c],["__file","showcase-zenrepublic.html.vue"]]),h=JSON.parse('{"path":"/showcase-zenrepublic.html","title":"Monster Hands ๐Ÿ’€","lang":"en-US","frontmatter":{"lang":"en-US","title":"Monster Hands ๐Ÿ’€","sidebar":false,"editLink":false,"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/monster hands.png"}],["meta",{"name":"og:description","content":"---\\nVisit website"}]],"description":"---\\nVisit website"},"headers":[{"level":3,"title":"Live","slug":"live","link":"#live","children":[]}],"git":{"updatedTime":1682497626000},"filePathRelative":"showcase-zenrepublic.md"}');export{m as comp,h as data}; diff --git a/assets/squeeze-to-scale-object-or-world-in-vr.html-C2ATGHYY.js b/assets/squeeze-to-scale-object-or-world-in-vr.html-C2ATGHYY.js new file mode 100644 index 000000000..1232c19fa --- /dev/null +++ b/assets/squeeze-to-scale-object-or-world-in-vr.html-C2ATGHYY.js @@ -0,0 +1,249 @@ +import{_ as n,r as h,o as k,c as l,a as i,b as t,e as p}from"./app-CRZRGfEE.js";const e={};function r(C,s){const a=h("contribution-header");return k(),l("div",null,[s[0]||(s[0]=i("p",null,[i("a",{href:"/docs/community/contributions"},"Overview")],-1)),t(a,{url:"https://github.com/Web3Kev",author:"Web3Kev",page:"/docs/community/contributions/web3kev",profileImage:"https://avatars.githubusercontent.com/u/106066970?s=100&v=4",githubUrl:"https://github.com/needle-tools/needle-engine-support/discussions/159",title:"Squeeze to Scale (Object or World) in VR",gradient:"True"}),s[1]||(s[1]=p(`

    The following code enables you to use both controllers in VR (tested on Quest) and scale the player's perspective (XRRig) by squeezing the grab triggers and moving the controllers closer (pinch out) or further apart (pinch in). The boolean allowWorldScaling has to be ticked in unity for that to work.

    Upon selecting a draggable object (Drag controls script), the player can scale up or down that object, while keeping the finger on the trigger and squeezing both grab buttons and moving the hands closer or apart.

    The current script enables you to visually see the scale. Create a world canvas with a text component as a child. Assign the world canvas to scaleTextObject and the text to scaleText. scaleTextObject will then spawn in front of the player and follow the head movement whenever scaling.

    At the moment the position of the hands (controllers) is done by finding the avatar's hands. I couldn't make it work otherwise. If you find a better way please share.

    import { Behaviour, WebXR,serializeable, WebXREvent,WebXRAvatar,GameObject, AvatarMarker,Text} from "@needle-tools/engine";
    +import { Object3D, Vector3,Quaternion,PerspectiveCamera} from "three";
    +
    +export class SqueezeScale extends Behaviour {
    +
    +   
    +    private webXR?: WebXR;
    +
    +    private selectedObj: Object3D| null = null;
    +
    +    @serializeable(Object3D)
    +    scaleTextObject: Object3D| null = null;
    +    
    +    @serializeable(Text)
    +    scaleText?: Text;
    +
    +    public allowWorldScaling: boolean =false;
    +
    +    private leftSqueeze:boolean=false;
    +    private rightSqueeze:boolean=false;
    +
    +    private bothSqueezeStarted=false;
    +
    +    private rigScaleUpdated=false;
    +
    +    private initialDistance:number=1;
    +    private initialScale:number=1;
    +    private newScale:number | null=null;
    +
    +    private leftHand?:Object3D;
    +    private rightHand?:Object3D;
    +    private head?:Object3D;
    +
    +    start(): void {
    +
    +        let _webxr=GameObject.findObjectOfType(WebXR);
    +        if(_webxr)
    +        {
    +            this.webXR=_webxr;
    +            console.log("webxr found");
    +        }
    +
    +        //Wait for XR Session
    +        WebXR.addEventListener(WebXREvent.XRStarted, () => {
    +            //listen to squeeze events
    +            this.context.xrSession?.addEventListener("squeezestart", (event) => { this.onSqueezeEvent(event,true); });
    +            this.context.xrSession?.addEventListener("squeezeend", (event) => { this.onSqueezeEvent(event,false); });
    +        });
    +    }
    +
    +
    +    onSqueezeEvent(event: XRInputSourceEvent, status:boolean) {
    +        
    +        if(event.inputSource.handedness==="right")
    +        {
    +            this.rightSqueeze=status;
    +        }
    +        
    +        if(event.inputSource.handedness==="left")
    +        {
    +            this.leftSqueeze=status;
    +        }
    +    }
    +
    +    update(){
    +        
    +        if(this.context.isInVR)
    +        {
    +            //cache object selected if any
    +            this.objectGrab();
    +            
    +            //if both grips are squeezed 
    +            if(this.leftSqueeze && this.rightSqueeze)
    +            {
    +                //if object is selected either in the left or right controller (only one)
    +                if(this.selectedObj!=null)
    +                {
    +                    //after initial distance value has been set
    +                    if(this.bothSqueezeStarted)
    +                    {
    +                        //get current distance between controllers
    +                        const scaleValue=this.calculateDistance();
    +
    +                        //get distance change since beginning of squeeze to get a "pinch in/out" effect
    +                        this.newScale=this.initialScale+scaleValue-this.initialDistance;
    +
    +                        //avoid 0 and negative scales
    +                        if(this.newScale<0.001){this.newScale=0.001;}
    +
    +                        // scale object according to new distance since initial distance
    +                        this.selectedObj.scale.x=this.newScale;
    +                        this.selectedObj.scale.y=this.newScale;
    +                        this.selectedObj.scale.z=this.newScale;
    +
    +                        this.showVisual(this.newScale,"Object :");
    +                    }
    +                    else
    +                    {
    +                        //get initial distance value (only once at a new squeeze both hands event)
    +                        this.bothSqueezeStarted=true;
    +
    +                        this.initialDistance=this.calculateDistance();
    +
    +                        //cache object's initial scale
    +                        this.initialScale=this.selectedObj.scale.x;
    +                    }
    +                }
    +                else
    +                {
    +                    //scale world ?
    +                    if(this.webXR?.Rig && this.allowWorldScaling)
    +                    {
    +                        //after initial distance value has been set
    +                        if(this.bothSqueezeStarted)
    +                        {
    +                            //get current distance between controllers
    +                            const scaleValue=this.calculateDistance();
    +
    +                            //get distance change since beginning of squeeze to get a "pinch in/out" effect
    +                            this.newScale=this.initialScale+scaleValue-this.initialDistance;
    +
    +                            //avoid 0 and negative scales
    +                            if(this.newScale<0.001){this.newScale=0.001;}
    +
    +                            this.showVisual(this.newScale, "World :");
    +
    +                            this.rigScaleUpdated=true;
    +                        }
    +                        else
    +                        {
    +                            //get initial distance value (only once at a new squeeze both hands event)
    +                            this.bothSqueezeStarted=true;
    +
    +                            this.initialDistance=this.calculateDistance();
    +
    +                            //cache object's initial scale
    +                            this.initialScale=this.webXR.Rig.scale.x;
    +                        }
    +                    }
    +                }
    +                
    +            }
    +            else
    +            {
    +                //reset values
    +                this.bothSqueezeStarted=false;
    +
    +                //if world has been scaled, scale rig accordingly at the end of squeezing and once only
    +                if(this.webXR?.Rig && this.rigScaleUpdated && this.newScale)
    +                {
    +                    //change rig scale
    +                    this.webXR.Rig.scale.set(this.newScale, this.newScale, this.newScale);
    +                    this.webXR.Rig.updateMatrixWorld();
    +                    
    +                    const cam = this.context.mainCamera as PerspectiveCamera;
    +                    cam.near=this.newScale>2?0.0001:0.2;
    +                    cam.updateProjectionMatrix();
    +
    +                    //reset
    +                    this.rigScaleUpdated=false;
    +                }
    +
    +                if(this.scaleTextObject)
    +                {
    +                    this.scaleTextObject.visible=false;
    +                }
    +
    +                this.newScale=null;    
    +            }
    +        }
    +    }
    +
    +    private calculateDistance():number
    +    {
    +        let distance=1;
    +
    +        if(this.leftHand && this.rightHand)
    +        {
    +            
    +            const left=this.leftHand.position;
    +            const right=this.rightHand.position;
    +
    +            // Calculate the difference between the positions
    +            const dx = left.x - right.x;
    +            const dy = left.y - right.y;
    +            const dz = left.z - right.z;
    +
    +            // Calculate the distance using the Euclidean distance formula
    +            distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
    +        }
    +        else
    +        {
    +            //set positions of controllers from your avatar (only once)
    +            let allAvatars = AvatarMarker.instances;
    +            if(allAvatars.length>0)
    +            {
    +                for (let i=0;i<allAvatars.length;i++)
    +                {
    +                    if(allAvatars[i].isLocalAvatar())
    +                    {
    +                        const av=allAvatars[i].avatar as WebXRAvatar;
    +                        if(av!=null)
    +                        {
    +                            this.leftHand=av.handLeft as Object3D;
    +                            this.rightHand=av.handRight as Object3D;
    +                            this.head = av.head as Object3D;
    +                        }
    +                    }
    +                }
    +            }
    +        }
    +        
    +        return distance;
    +    }
    +
    +    showVisual(scale:number, mesg:string):void
    +    {
    +        if(this.scaleTextObject && this.head && this.scaleText)
    +        {
    +            this.scaleTextObject.visible=true;
    +
    +            const offset = new Vector3(0,0,7);
    +            offset.applyQuaternion(this.head.quaternion);
    +
    +            this.scaleTextObject.position.copy(this.head.position.add(offset));
    +
    +            const roundedNum= +scale.toFixed(3);
    +            this.scaleText.text=mesg+" "+roundedNum;
    +        }
    +        
    +    }
    +    
    +
    +    objectGrab():void
    +    {
    +        if(this.webXR?.RightController?.grabbed?.selected) 
    +        {
    +            this.selectedObj = this.webXR.RightController.grabbed.selected;
    +        }
    +        else if(this.webXR?.LeftController?.grabbed?.selected)
    +        {
    +            this.selectedObj = this.webXR.LeftController.grabbed.selected;
    +        }
    +        else
    +        {
    +            this.selectedObj=null;
    +        }
    +    }
    +}
    `,5))])}const y=n(e,[["render",r],["__file","squeeze-to-scale-object-or-world-in-vr.html.vue"]]),g=JSON.parse('{"path":"/community/contributions/web3kev/squeeze-to-scale-object-or-world-in-vr","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/web3kev: squeeze to scale object or world in vr.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{y as comp,g as data}; diff --git a/assets/stackblitz-DA3DcIUI.js b/assets/stackblitz-DA3DcIUI.js new file mode 100644 index 000000000..8da975295 --- /dev/null +++ b/assets/stackblitz-DA3DcIUI.js @@ -0,0 +1,33 @@ +import{_ as h,o as f,c as b,a as g,f as w}from"./app-CRZRGfEE.js";function x(e){return e.startsWith("@code")?e.replace(/^@code/,"./code-samples/"):e}async function k(e,n,t,o){let s=await(await fetch(n)).text();o&&(s=o(s)),t[e]=s}async function c(e,n,t,o,a){e.push(k(n,t,o,a))}async function y(e,n){const t=[];c(t,"package.json","https://raw.githubusercontent.com/needle-engine/vite-template/main/package.json",e),c(t,"package-lock.json","https://raw.githubusercontent.com/needle-engine/vite-template/main/package-lock.json",e),c(t,"src/styles/style.css","https://raw.githubusercontent.com/needle-engine/vite-template/main/src/styles/style.css",e),c(t,"vite.config.js","https://raw.githubusercontent.com/needle-engine/vite-template/main/vite.config.js",e,o=>o.replace("needlePlugins(command, needleConfig)","needlePlugins(command, needleConfig, { noPoster: true })")),c(t,"tsconfig.json","https://raw.githubusercontent.com/needle-engine/vite-template/main/tsconfig.json",e),c(t,"index.html","https://raw.githubusercontent.com/needle-engine/vite-template/main/index.html",e,o=>o.replace(/\/,``)),await Promise.all(t)}async function j(e,n){var p,u;let t=`// Generated via ${window.location.href} at ${new Date().toISOString()} +import { NeedleEngine, RemoteSkybox, GameObject, ObjectRaycaster } from '@needle-tools/engine'; +import * as THREE from 'three'; +`;const o=x(n),a=window.location,s=a.pathname.split("/").slice(0,-1).join("/"),i=`${a.origin}${s}/${o}`,r=await(await fetch(i)).text(),d="src/main.ts",l=r.match(/export class\s+?(?.+?)\s+extends Behaviour/),m=(u=(p=l==null?void 0:l.groups)==null?void 0:p.component_name)==null?void 0:u.trim();return console.log(m),t+=` +// SAMPLE SCRIPT START +`+r+` +// SAMPLE SCRIPT END +`,t+=` + +NeedleEngine.addContextCreatedCallback((args) => { + const context = args.context; + const scene = context.scene; + + const grid = new THREE.GridHelper(); + scene.add(grid); + + const geometry = new THREE.BoxGeometry(1, 1, 1); + const material = new THREE.MeshStandardMaterial({ color: 0xdddddd }); + const cube = new THREE.Mesh(geometry, material); + cube.name = "Cube"; + cube.position.y += 0.5; + scene.add(cube); + GameObject.addComponent(cube, new ${m}()); + ${r.includes("IPointerClickHandler")?"GameObject.addNewComponent(cube, ObjectRaycaster)":""} + + const remoteSkybox = new RemoteSkybox(); + remoteSkybox.background = false; + remoteSkybox.url = + 'https://dl.polyhaven.org/file/ph-assets/HDRIs/hdr/1k/cyclorama_hard_light_1k.hdr'; + GameObject.addComponent(grid, remoteSkybox); +}); +`,e[d]=t,d}const P={props:{file:String},methods:{async openProject(){const e={};await y(e,"https://github.com/needle-engine/vite-template/raw/main/assets/basic.glb");const n=await j(e,this.file),t=n.split("/").pop();StackBlitzSDK.openProject({files:{...e,"index.ts":`import './src/main'; +import '${n}';`},template:"node",title:`${t}`,description:"This is a generated project via https://docs.needle.engine. Please note that this feature is experimental(!) and the project might not work as expected."},{newWindow:!0,openFile:n})}}},S={class:"code"};function v(e,n,t,o,a,s){return f(),b("div",null,[g("button",{onClick:n[0]||(n[0]=(...i)=>s.openProject&&s.openProject(...i)),class:"plausible-event-name=Click+Create+Stackblitz+Project"}," Open in StackBlitz "),g("div",S,[w(e.$slots,"default")])])}const _=h(P,[["render",v],["__file","stackblitz.vue"]]);export{_ as default}; diff --git a/assets/style-rKjGPieq.css b/assets/style-rKjGPieq.css new file mode 100644 index 000000000..3ed50854e --- /dev/null +++ b/assets/style-rKjGPieq.css @@ -0,0 +1 @@ +@charset "UTF-8";@import"https://fonts.googleapis.com/css2?family=Nunito+Sans:opsz,wght@6..12,300..900&display=swap";.vp-copy-code-button{position:absolute;top:.5em;right:.5em;z-index:5;width:2.5rem;height:2.5rem;padding:0;border-width:0;border-radius:.5rem;background:transparent;outline:none;opacity:0;cursor:pointer;transition:opacity .4s}@media print{.vp-copy-code-button{display:none}}.vp-copy-code-button:before{content:"";display:inline-block;width:1.25rem;height:1.25rem;padding:.625rem;background:currentcolor;color:var(--copy-code-c-text);font-size:1.25rem;-webkit-mask-image:var(--code-copy-icon);mask-image:var(--code-copy-icon);-webkit-mask-position:50%;mask-position:50%;-webkit-mask-size:1em;mask-size:1em;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.vp-copy-code-button:focus,.vp-copy-code-button.copied{opacity:1}.vp-copy-code-button:hover,.vp-copy-code-button.copied{background:var(--copy-code-c-hover)}.vp-copy-code-button.copied:before{-webkit-mask-image:var(--code-copied-icon);mask-image:var(--code-copied-icon)}.vp-copy-code-button.copied:after{content:attr(data-copied);position:absolute;top:0;right:calc(100% + .25rem);display:block;height:1.25rem;padding:.625rem;border-radius:.5rem;background:var(--copy-code-c-hover);color:var(--copy-code-c-text);font-weight:500;line-height:1.25rem;white-space:nowrap}.no-copy-code .vp-copy-code-button{display:none}body:not(.no-copy-code) div[class*=language-]:hover:before{display:none}body:not(.no-copy-code) div[class*=language-]:hover .vp-copy-code-button{opacity:1}:root{--code-copy-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23808080' stroke-width='2'%3e%3cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2' /%3e%3c/svg%3e");--code-copied-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23808080' stroke-width='2'%3e%3cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2m-6 9 2 2 4-4' /%3e%3c/svg%3e");--copy-code-c-text: var(--code-c-line-number);--copy-code-c-hover: var(--code-c-highlight-bg)}.hint-container{position:relative;border-color:var(--hint-c-accent);background:var(--hint-c-bg);transition:background var(--vp-t-color),border-color var(--vp-t-color),color var(--vp-t-color)}@media print{.hint-container{page-break-inside:avoid}}.hint-container>.hint-container-title{color:var(--hint-c-title)}.hint-container :not(pre)>code{background:var(--note-c-soft)}.hint-container .hint-container-title{position:relative;margin-block:.75em;font-weight:600;line-height:1.25}.hint-container.important,.hint-container.info,.hint-container.note,.hint-container.tip,.hint-container.warning,.hint-container.caution{margin:.85rem 0;padding:.25rem 1rem;border-inline-start-width:.3rem;border-inline-start-style:solid;border-radius:.5rem;color:inherit}@media (max-width: 419px){.hint-container.important,.hint-container.info,.hint-container.note,.hint-container.tip,.hint-container.warning,.hint-container.caution{margin-inline:-.75rem}}.hint-container.important .hint-container-title,.hint-container.info .hint-container-title,.hint-container.note .hint-container-title,.hint-container.tip .hint-container-title,.hint-container.warning .hint-container-title,.hint-container.caution .hint-container-title{padding-inline-start:1.75rem}@media print{.hint-container.important .hint-container-title,.hint-container.info .hint-container-title,.hint-container.note .hint-container-title,.hint-container.tip .hint-container-title,.hint-container.warning .hint-container-title,.hint-container.caution .hint-container-title{padding-inline-start:0}}.hint-container.important .hint-container-title:before,.hint-container.info .hint-container-title:before,.hint-container.note .hint-container-title:before,.hint-container.tip .hint-container-title:before,.hint-container.warning .hint-container-title:before,.hint-container.caution .hint-container-title:before{content:" ";position:absolute;inset-inline-start:0;top:calc(50% - .6125em);width:1.25em;height:1.25em;background-position:left;background-repeat:no-repeat}@media print{.hint-container.important .hint-container-title:before,.hint-container.info .hint-container-title:before,.hint-container.note .hint-container-title:before,.hint-container.tip .hint-container-title:before,.hint-container.warning .hint-container-title:before,.hint-container.caution .hint-container-title:before{display:none}}.hint-container.important p,.hint-container.info p,.hint-container.note p,.hint-container.tip p,.hint-container.warning p,.hint-container.caution p{line-height:1.5}.hint-container.important a,.hint-container.info a,.hint-container.note a,.hint-container.tip a,.hint-container.warning a,.hint-container.caution a{color:var(--vp-c-accent)}.hint-container.important{--hint-c-accent: var(--important-c-accent);--hint-c-bg: var(--important-c-light);--hint-c-title: var(--important-c-dark);--hint-c-soft: var(--important-c-soft)}[data-theme=dark] .hint-container.important{--hint-c-bg: var(--important-c-dark);--hint-c-title: var(--important-c-light)}.hint-container.important>.hint-container-title:before{background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Cpath d='M512 981.333a84.992 84.992 0 0 1-84.907-84.906h169.814A84.992 84.992 0 0 1 512 981.333zm384-128H128v-42.666l85.333-85.334v-256A298.325 298.325 0 0 1 448 177.92V128a64 64 0 0 1 128 0v49.92a298.325 298.325 0 0 1 234.667 291.413v256L896 810.667v42.666zm-426.667-256v85.334h85.334v-85.334h-85.334zm0-256V512h85.334V341.333h-85.334z' fill='%23a371f7'/%3E%3C/svg%3E")}.hint-container.info{--hint-c-accent: var(--info-c-accent);--hint-c-bg: var(--info-c-light);--hint-c-title: var(--info-c-dark);--hint-c-soft: var(--info-c-soft)}[data-theme=dark] .hint-container.info{--hint-c-bg: var(--info-c-dark);--hint-c-title: var(--info-c-light)}.hint-container.info>.hint-container-title:before{background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-11v6h2v-6h-2zm0-4v2h2V7h-2z' fill='%234cb3d4'/%3E%3C/svg%3E")}.hint-container.note{--hint-c-accent: var(--note-c-accent);--hint-c-bg: var(--note-c-light);--hint-c-title: var(--note-c-dark);--hint-c-soft: var(--note-c-soft)}[data-theme=dark] .hint-container.note{--hint-c-bg: var(--note-c-dark);--hint-c-title: var(--note-c-light)}.hint-container.note>.hint-container-title:before{background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-11v6h2v-6h-2zm0-4v2h2V7h-2z' fill='%23ccc'/%3E%3C/svg%3E")}.hint-container.tip{--hint-c-accent: var(--tip-c-accent);--hint-c-bg: var(--tip-c-light);--hint-c-title: var(--tip-c-dark);--hint-c-soft: var(--tip-c-soft)}[data-theme=dark] .hint-container.tip{--hint-c-bg: var(--tip-c-dark);--hint-c-title: var(--tip-c-light)}.hint-container.tip>.hint-container-title:before{background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23009400' d='M7.941 18c-.297-1.273-1.637-2.314-2.187-3a8 8 0 1 1 12.49.002c-.55.685-1.888 1.726-2.185 2.998H7.94zM16 20v1a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-1h8zm-3-9.995V6l-4.5 6.005H11v4l4.5-6H13z'/%3E%3C/svg%3E")}.hint-container.warning{--hint-c-accent: var(--warning-c-accent);--hint-c-bg: var(--warning-c-light);--hint-c-title: var(--warning-c-dark);--hint-c-soft: var(--warning-c-soft)}[data-theme=dark] .hint-container.warning{--hint-c-bg: var(--warning-c-dark);--hint-c-title: var(--warning-c-light)}.hint-container.warning>.hint-container-title:before{background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Cpath d='M576.286 752.57v-95.425q0-7.031-4.771-11.802t-11.3-4.772h-96.43q-6.528 0-11.3 4.772t-4.77 11.802v95.424q0 7.031 4.77 11.803t11.3 4.77h96.43q6.528 0 11.3-4.77t4.77-11.803zm-1.005-187.836 9.04-230.524q0-6.027-5.022-9.543-6.529-5.524-12.053-5.524H456.754q-5.524 0-12.053 5.524-5.022 3.516-5.022 10.547l8.538 229.52q0 5.023 5.022 8.287t12.053 3.265h92.913q7.032 0 11.803-3.265t5.273-8.287zM568.25 95.65l385.714 707.142q17.578 31.641-1.004 63.282-8.538 14.564-23.354 23.102t-31.892 8.538H126.286q-17.076 0-31.892-8.538T71.04 866.074q-18.582-31.641-1.004-63.282L455.75 95.65q8.538-15.57 23.605-24.61T512 62t32.645 9.04 23.605 24.61z' fill='%23e6a700'/%3E%3C/svg%3E")}.hint-container.caution{--hint-c-accent: var(--caution-c-accent);--hint-c-bg: var(--caution-c-light);--hint-c-title: var(--caution-c-dark);--hint-c-soft: var(--caution-c-soft)}[data-theme=dark] .hint-container.caution{--hint-c-bg: var(--caution-c-dark);--hint-c-title: var(--caution-c-light)}.hint-container.caution>.hint-container-title:before{background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2c5.523 0 10 4.477 10 10v3.764a2 2 0 0 1-1.106 1.789L18 19v1a3 3 0 0 1-2.824 2.995L14.95 23a2.5 2.5 0 0 0 .044-.33L15 22.5V22a2 2 0 0 0-1.85-1.995L13 20h-2a2 2 0 0 0-1.995 1.85L9 22v.5c0 .171.017.339.05.5H9a3 3 0 0 1-3-3v-1l-2.894-1.447A2 2 0 0 1 2 15.763V12C2 6.477 6.477 2 12 2zm-4 9a2 2 0 1 0 0 4 2 2 0 0 0 0-4zm8 0a2 2 0 1 0 0 4 2 2 0 0 0 0-4z' fill='%23e13238'/%3E%3C/svg%3E")}.hint-container.details{--detail-c-bg: var(--detail-c-light);--detail-c-icon: var(--detail-c-icon-light);position:relative;display:block;margin:1rem 0;padding:1.5rem;border-radius:.5rem;background:var(--detail-c-bg);transition:background var(--vp-t-transform),color var(--vp-t-transform)}@media (max-width: 419px){.hint-container.details{margin-inline:-.75rem}}[data-theme=dark] .hint-container.details{--detail-c-bg: var(--detail-c-dark);--detail-c-icon: var(--detail-c-icon-dark)}.hint-container.details h4{margin-top:0}.hint-container.details figure:last-child,.hint-container.details p:last-child{margin-bottom:0;padding-bottom:0}.hint-container.details a{color:var(--vp-c-accent)}.hint-container.details :not(pre)>code{background:var(--detail-c-soft)}.hint-container.details summary{position:relative;margin:-1.5rem;padding-block:1.5rem;padding-inline:4rem 1.5rem;list-style:none;cursor:pointer}.hint-container.details summary::-webkit-details-marker{display:none}.hint-container.details summary::marker{color:transparent;font-size:0}.hint-container.details summary:before,.hint-container.details summary:after{content:" ";position:absolute;inset-inline-start:1.5rem;top:calc(50% - .75rem);width:1.5rem;height:1.5rem}.hint-container.details summary:before{border-radius:50%;background:var(--detail-c-icon);transition:background var(--vp-t-color),transform var(--vp-t-transform)}.hint-container.details summary:after{background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgb(0,0,0,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E");line-height:normal;transition:transform var(--vp-t-transform);transform:rotate(90deg)}[data-theme=dark] .hint-container.details summary:after{background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgb(255,255,255,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E")}.hint-container.details[open]>summary{margin-bottom:.5em}.hint-container.details[open]>summary:after{transform:rotate(180deg)}:root{--important-c-accent: #a371f7;--important-c-light: #f4eefe;--important-c-dark: #230555;--important-c-soft: rgb(163 113 247 / 10%);--info-c-accent: #4cb3d4;--info-c-light: #eef9fd;--info-c-dark: #193c47;--info-c-soft: rgb(76 179 212 / 10%);--note-c-accent: #ccc;--note-c-light: #fdfdfe;--note-c-dark: #474748;--note-c-soft: rgb(212 213 216 / 20%);--tip-c-accent: #009400;--tip-c-light: #e6f6e6;--tip-c-dark: #003100;--tip-c-soft: rgb(0 148 0 / 15%);--warning-c-accent: #e6a700;--warning-c-light: #fff8e6;--warning-c-dark: #4d3800;--warning-c-soft: rgb(230 167 0 / 15%);--caution-c-accent: #e13238;--caution-c-light: #ffebec;--caution-c-dark: #4b1113;--caution-c-soft: rgb(225 50 56 / 15%);--detail-c-light: #eee;--detail-c-dark: #333;--detail-c-icon-light: #ccc;--detail-c-icon-dark: #555;--detail-c-soft: rgb(127 127 127 / 15%)}:root{--medium-zoom-z-index: 100;--medium-zoom-c-bg: var(--vp-c-bg-elv, #fff);--medium-zoom-opacity: 1}.medium-zoom-overlay{z-index:var(--medium-zoom-z-index);background-color:var(--medium-zoom-c-bg)!important}.medium-zoom-overlay~img{z-index:calc(var(--medium-zoom-z-index) + 1)}.medium-zoom--opened .medium-zoom-overlay{opacity:var(--medium-zoom-opacity)}:root{--nprogress-c: var(--vp-c-accent);--nprogress-z-index: 1031}#nprogress{pointer-events:none}#nprogress .bar{position:fixed;top:0;left:0;z-index:var(--nprogress-z-index);width:100%;height:2px;background:var(--nprogress-c)}.vp-badge{display:inline-block;vertical-align:top;height:18px;padding:0 6px;border-radius:3px;color:var(--vp-c-accent-text);font-weight:600;font-size:14px;line-height:18px;transition:color var(--vp-t-color),background-color var(--vp-t-color)}.vp-badge.tip{background-color:var(--c-badge-tip);color:var(--c-badge-tip-text)}.vp-badge.warning{background-color:var(--c-badge-warning);color:var(--c-badge-warning-text)}.vp-badge.danger{background-color:var(--c-badge-danger);color:var(--c-badge-danger-text)}.vp-badge+.vp-badge{margin-left:5px}.code-group-nav{margin-top:.85rem;margin-bottom:calc(-1.7rem - 6px);padding-top:10px;padding-bottom:calc(1.7rem - 6px);padding-left:10px;border-top-left-radius:6px;border-top-right-radius:6px;background-color:var(--vp-c-code-tab-bg);transition:background-color var(--t-color)}@media (max-width: 419px){.code-group-nav{margin-right:-1.5rem;margin-left:-1.5rem;border-radius:0}}.code-group-nav-tab{padding:5px;border:0;background-color:transparent;color:var(--vp-c-code-tab-title);font-weight:600;font-size:.85em;line-height:1.4;cursor:pointer}.code-group-nav-tab:focus{outline:none}.code-group-nav-tab:focus-visible{outline:1px solid}.code-group-nav-tab.active{border-bottom:var(--vp-c-code-tab-active) 1px solid}.code-group-item{display:none}.code-group-item.active{display:block}.code-group-item>pre{background-color:orange}.vp-features{display:flex;flex-wrap:wrap;place-content:stretch space-between;align-items:flex-start;margin-top:2.5rem;padding:1.2rem 0;border-top:1px solid var(--vp-c-gutter);transition:border-color var(--vp-t-color)}@media (max-width: 719px){.vp-features{flex-direction:column}}.vp-feature{flex-grow:1;flex-basis:30%;max-width:30%}@media (max-width: 719px){.vp-feature{max-width:100%;padding:0 2.5rem}}.vp-feature h2{padding-bottom:0;border-bottom:none;font-weight:500;font-size:1.4rem}@media (max-width: 419px){.vp-feature h2{font-size:1.25rem}}.vp-feature p{color:var(--vp-c-text-mute)}.vp-footer{padding:2.5rem;border-top:1px solid var(--vp-c-border);color:var(--vp-c-text-mute);text-align:center;transition:border-color var(--vp-t-color)}.vp-hero{text-align:center}.vp-hero-image{display:block;max-width:100%;max-height:280px;margin:3rem auto 1.5rem}@media (max-width: 419px){.vp-hero-image{max-height:210px;margin:2rem auto 1.2rem}}#main-title{font-size:3rem}@media (max-width: 419px){#main-title{font-size:2rem}}#main-title,.vp-hero-description,.vp-hero-actions{margin:1.8rem auto}@media (max-width: 419px){#main-title,.vp-hero-description,.vp-hero-actions{margin:1.2rem auto}}.vp-hero-actions{display:flex;flex-wrap:wrap;gap:1rem;justify-content:center}.vp-hero-description{max-width:35rem;color:var(--vp-c-text-mute);font-size:1.6rem;line-height:1.3}@media (max-width: 419px){.vp-hero-description{font-size:1.2rem}}.vp-hero-action-button{display:inline-block;box-sizing:border-box;padding:.8rem 1.6rem;border:2px solid var(--vp-c-accent);border-radius:4px;font-size:1.2rem;transition:background-color border-color color var(--vp-t-color)}@media (max-width: 419px){.vp-hero-action-button{padding:.6rem 1.2rem;font-size:1rem}}.vp-hero-action-button.primary{background-color:var(--vp-c-accent);color:var(--vp-c-accent-text)}.vp-hero-action-button.secondary{background-color:var(--vp-c-bg);color:var(--vp-c-accent)}.vp-hero-action-button.secondary:hover{color:var(--vp-c-accent-text)}.vp-hero-action-button:hover{border-color:var(--vp-c-accent-hover);background-color:var(--vp-c-accent-hover)}.vp-home{display:block;max-width:var(--homepage-width);margin:0 auto;padding:var(--navbar-height) 2rem 0}@media (max-width: 419px){.vp-home{padding-right:1.5rem;padding-left:1.5rem}}.vp-home .theme-default-content{margin:0;padding:0}.vp-site-logo{vertical-align:top;height:var(--navbar-line-height);margin-right:var(--navbar-padding-v)}.vp-site-name{position:relative;color:var(--vp-c-text);font-weight:600;font-size:1.3rem}@media screen and (max-width: 719px){.vp-site-name{display:block;overflow:hidden;width:calc(100vw - 11rem);text-overflow:ellipsis;white-space:nowrap}}.vp-dropdown-enter-from,.vp-dropdown-leave-to{height:0!important}.vp-navbar-dropdown-wrapper{cursor:pointer}.vp-navbar-dropdown-wrapper:not(.mobile){height:1.8rem}.vp-navbar-dropdown-wrapper:not(.mobile):hover .vp-navbar-dropdown,.vp-navbar-dropdown-wrapper:not(.mobile).open .vp-navbar-dropdown{display:block!important}.vp-navbar-dropdown-wrapper.mobile .vp-navbar-dropdown{overflow:hidden;transition:height .1s ease-out;padding-top:.5rem}.vp-navbar-dropdown-wrapper:not(.mobile) .vp-navbar-dropdown{position:absolute;top:100%;right:0;display:none;overflow-y:auto;box-sizing:border-box;height:auto!important;max-height:calc(100vh - 2.7rem);margin:0;padding:.6rem 0;border:1px solid var(--vp-c-gutter);border-radius:.5rem;background-color:var(--vp-c-bg-elv);text-align:left;white-space:nowrap}.vp-navbar-dropdown-title{display:block;padding:inherit;border:none;background:transparent;color:var(--vp-c-text);font-weight:500;font-size:.9rem;font-family:inherit;line-height:1.4rem;cursor:inherit}.vp-navbar-dropdown-wrapper.mobile .vp-navbar-dropdown-title{display:none}.vp-navbar-dropdown-title:hover{border-color:transparent}.vp-navbar-dropdown-title-mobile{display:none;padding:inherit;border:none;background:transparent;color:var(--vp-c-text);font-weight:600;font-size:inherit;font-family:inherit;line-height:1.4rem;cursor:inherit}.vp-navbar-dropdown-wrapper.mobile .vp-navbar-dropdown-title-mobile{display:block}.vp-navbar-dropdown-title-mobile:hover{color:var(--vp-c-accent)}.vp-navbar-dropdown-item{color:inherit;line-height:1.7rem}.vp-navbar-dropdown-item a{position:relative;display:block;margin-bottom:0;padding:0 1.5rem 0 1.25rem;border-bottom:none;font-weight:400;line-height:1.7rem}.vp-navbar-dropdown-item a:hover,.vp-navbar-dropdown-item a.route-link-active{color:var(--vp-c-accent)}.vp-navbar-dropdown-item a.route-link-active:after{content:"";position:absolute;top:calc(50% - 2px);left:9px;width:0;height:0;border-top:3px solid transparent;border-bottom:3px solid transparent;border-left:5px solid var(--vp-c-accent)}.vp-navbar-dropdown-wrapper.mobile .vp-navbar-dropdown-item>a{font-size:15px;line-height:2rem}.vp-navbar-dropdown-subtitle{margin:.45rem 0 0;padding:1rem 0 .45rem;border-top:1px solid var(--vp-c-gutter);font-size:.9rem}.vp-navbar-dropdown-wrapper.mobile .vp-navbar-dropdown-subtitle{margin-top:0;padding-top:0;padding-bottom:0;border-top:0;font-size:15px;line-height:2rem}.vp-navbar-dropdown-item:first-child .vp-navbar-dropdown-subtitle{margin-top:0;padding-top:0;border-top:0}.vp-navbar-dropdown-subtitle>span{padding:0 1.5rem 0 1.25rem}.vp-navbar-dropdown-subtitle>a{font-weight:inherit}.vp-navbar-dropdown-subtitle>a.route-link-active:after{display:none}.vp-navbar-dropdown-subitem-wrapper{padding:0;list-style:none}.vp-navbar-dropdown-subitem{font-size:.9em}.vp-navbar-dropdown-wrapper.mobile .vp-navbar-dropdown-subitem{padding-left:1rem;font-size:14px}.vp-navbar-items{display:inline-block}@media print{.vp-navbar-items{display:none}}.vp-navbar-items a{display:inline-block;color:inherit;line-height:1.4rem}.vp-navbar-items a:hover,.vp-navbar-items a.route-link-active{color:var(--vp-c-text)}.vp-navbar-item{position:relative;display:inline-block;margin-left:1.5rem;line-height:var(--navbar-line-height)}@media (max-width: 719px){.vp-navbar-item{margin-left:0}}.vp-navbar-item:first-child{margin-left:0}.vp-navbar-item a:hover,.vp-navbar-item a.route-link-active{color:var(--vp-c-accent)}.vp-navbar-item>a:hover,.vp-navbar-item>a.route-link-active{margin-bottom:-2px;border-bottom:2px solid var(--vp-c-accent)}@media (max-width: 719px){.vp-navbar-item>a:hover,.vp-navbar-item>a.route-link-active{margin-bottom:0;border-bottom:none}}.vp-toggle-color-mode-button{display:flex;margin:auto;margin-left:1rem;border:0;background:none;color:var(--vp-c-text);opacity:.8;cursor:pointer}@media print{.vp-toggle-color-mode-button{display:none}}.vp-toggle-color-mode-button:hover{opacity:1}.vp-toggle-color-mode-button .light-icon,.vp-toggle-color-mode-button .dark-icon{width:1.25rem;height:1.25rem}.vp-toggle-sidebar-button{position:absolute;top:.6rem;left:1rem;display:none;padding:.6rem;cursor:pointer}@media screen and (max-width: 719px){.vp-toggle-sidebar-button{display:block}}.vp-toggle-sidebar-button .icon{display:flex;flex-direction:column;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;cursor:inherit}.vp-toggle-sidebar-button .icon span{display:inline-block;width:100%;height:2px;border-radius:2px;background-color:var(--vp-c-text);transition:transform var(--vp-t-transform)}.vp-toggle-sidebar-button .icon span:nth-child(2){margin:6px 0}.vp-theme-container.sidebar-open .vp-toggle-sidebar-button .icon span:nth-child(1){transform:rotate(45deg) translate3d(5.5px,5.5px,0)}.vp-theme-container.sidebar-open .vp-toggle-sidebar-button .icon span:nth-child(2){transform:scale3d(0,1,1)}.vp-theme-container.sidebar-open .vp-toggle-sidebar-button .icon span:nth-child(3){transform:rotate(-45deg) translate3d(6px,-6px,0)}.vp-theme-container.sidebar-open .vp-toggle-sidebar-button .icon span:nth-child(1),.vp-theme-container.sidebar-open .vp-toggle-sidebar-button .icon span:nth-child(3){transform-origin:center}.vp-navbar{--navbar-line-height: calc( var(--navbar-height) - 2 * var(--navbar-padding-v) );position:fixed;top:0;right:0;left:0;z-index:20;box-sizing:border-box;height:var(--navbar-height);padding:var(--navbar-padding-v) var(--navbar-padding-h);border-bottom:1px solid var(--vp-c-border);background-color:var(--vp-navbar-c-bg);line-height:var(--navbar-line-height);transition:background-color var(--vp-t-color),border-color var(--vp-t-color)}.vp-navbar-items-wrapper{position:absolute;top:var(--navbar-padding-v);right:var(--navbar-padding-h);display:flex;box-sizing:border-box;height:var(--navbar-line-height);padding-left:var(--navbar-padding-h);font-size:.9rem;white-space:nowrap}.vp-page-meta{max-width:var(--content-width);margin:0 auto;padding:.75rem 2.5rem;display:flex;flex-wrap:wrap;justify-content:space-between;overflow:auto}@media (max-width: 959px){.vp-page-meta{padding:2rem}}@media (max-width: 419px){.vp-page-meta{padding:1.5rem}}@media print{.vp-page-meta{margin:0!important;padding-right:0!important;padding-left:0!important}}@media (max-width: 719px){.vp-page-meta{display:block}}.vp-page-meta .vp-meta-item{flex-grow:1}.vp-page-meta .vp-meta-item .vp-meta-label{font-weight:500}.vp-page-meta .vp-meta-item .vp-meta-label:not(a){color:var(--vp-c-text-mute)}.vp-page-meta .vp-meta-item .vp-meta-info{color:var(--vp-c-text-mute);font-weight:400}.vp-page-meta .git-info{text-align:end}.vp-page-meta .edit-link{margin-top:.25rem;margin-right:.5rem;margin-bottom:.25rem;font-size:14px}@media print{.vp-page-meta .edit-link{display:none}}.vp-page-meta .edit-link .edit-icon{position:relative;bottom:-.125em;width:1em;height:1em;margin-right:.25em}.vp-page-meta .last-updated,.vp-page-meta .contributors{margin-top:.25rem;margin-bottom:.25rem;font-size:14px}@media (max-width: 719px){.vp-page-meta .last-updated,.vp-page-meta .contributors{font-size:13px;text-align:start}}.vp-page-nav{display:flex;flex-wrap:wrap;max-width:var(--content-width, 740px);min-height:2rem;margin-top:0;margin-right:auto;margin-left:auto;padding:1rem 2rem 0;border-top:1px solid var(--vp-c-gutter);transition:border-top var(--vp-t-color)}@media (max-width: 959px){.vp-page-nav{padding-right:1rem;padding-left:1rem}}@media print{.vp-page-nav{display:none}}.vp-page-nav .route-link{display:inline-block;flex-grow:1;margin:.25rem;padding:.25rem .5rem;border:1px solid var(--vp-c-gutter);border-radius:.25rem}.vp-page-nav .route-link:hover{background:var(--c-bg-soft)}.vp-page-nav .route-link .hint{color:var(--vp-c-text-mute);font-size:.875rem;line-height:2}.vp-page-nav .prev{text-align:start}.vp-page-nav .next{text-align:end}.vp-page{display:block;padding-top:var(--navbar-height);padding-bottom:2rem;padding-left:var(--sidebar-width)}@media (max-width: 959px){.vp-page{padding-left:var(--sidebar-width-mobile)}}@media (max-width: 719px){.vp-page{padding-left:0}}.vp-page .theme-default-content{max-width:var(--content-width);margin:0 auto;padding:2rem 2.5rem;padding-top:0}@media (max-width: 959px){.vp-page .theme-default-content{padding:2rem}}@media (max-width: 419px){.vp-page .theme-default-content{padding:1.5rem}}.vp-sidebar-item{border-left:.25rem solid transparent;color:var(--vp-c-text);cursor:default}.vp-sidebar-item:focus-visible{outline-width:1px;outline-offset:-1px}.vp-sidebar-item.vp-sidebar-heading{box-sizing:border-box;width:100%;margin:0;padding:.35rem 1.5rem .35rem 1.25rem;font-weight:700;font-size:1.1em;transition:color .15s ease}.vp-sidebar-item.vp-sidebar-heading+.vp-sidebar-children{overflow:hidden;transition:height .1s ease-out;margin-bottom:.75rem}.vp-sidebar-item.collapsible{cursor:pointer}.vp-sidebar-item:not(.vp-sidebar-heading){display:inline-block;box-sizing:border-box;width:100%;margin:0;padding:.35rem 1rem .35rem 2rem;font-weight:400;font-size:1em;line-height:1.4}.vp-sidebar-item:not(.vp-sidebar-heading)+.vp-sidebar-children{padding-left:1rem;font-size:.95em}.vp-sidebar-children .vp-sidebar-children .vp-sidebar-item:not(.vp-sidebar-heading){padding:.25rem 1rem .25rem 1.75rem}.vp-sidebar-children .vp-sidebar-children .vp-sidebar-item:not(.vp-sidebar-heading).active{border-left-color:transparent;font-weight:500}a.vp-sidebar-heading+.vp-sidebar-children .vp-sidebar-item:not(.vp-sidebar-heading).active{border-left-color:transparent}.vp-sidebar-item.active:not(p.vp-sidebar-heading){border-left-color:var(--vp-c-accent);color:var(--vp-c-accent);font-weight:600}a.vp-sidebar-item{cursor:pointer}a.vp-sidebar-item:hover{color:var(--vp-c-accent)}.vp-sidebar-items{margin:0;padding:1.5rem 0;list-style-type:none}@media (max-width: 719px){.vp-sidebar-items{padding:1rem 0}}.vp-sidebar-items ul{margin:0;padding:0;list-style-type:none}.vp-sidebar-items a{display:inline-block}.vp-sidebar{position:fixed;top:var(--navbar-height);bottom:0;left:0;z-index:10;overflow-y:auto;box-sizing:border-box;width:var(--sidebar-width);margin:0;border-right:1px solid var(--vp-c-border);background-color:var(--vp-sidebar-c-bg);font-size:16px;transition:transform var(--vp-t-transform),background-color var(--vp-t-color),border-color var(--vp-t-color);scrollbar-color:var(--vp-c-accent-bg) var(--vp-c-gutter);scrollbar-width:thin}@media (max-width: 959px){.vp-sidebar{width:var(--sidebar-width-mobile);font-size:15px}}@media (max-width: 719px){.vp-sidebar{top:0;padding-top:var(--navbar-height);transform:translate(-100%)}}.vp-sidebar::-webkit-scrollbar{width:7px}.vp-sidebar::-webkit-scrollbar-track{background-color:var(--vp-c-gutter)}.vp-sidebar::-webkit-scrollbar-thumb{background-color:var(--vp-c-accent-bg)}.vp-sidebar .vp-navbar-items{display:none;padding:.5rem 0 .75rem;border-bottom:1px solid var(--vp-c-gutter);transition:border-color var(--vp-t-color)}@media (max-width: 719px){.vp-sidebar .vp-navbar-items{display:block}.vp-sidebar .vp-navbar-items .vp-navbar-dropdown-item a.route-link-active:after{top:calc(1rem - 2px)}}.vp-sidebar .vp-navbar-items ul{margin:0;padding:0;list-style-type:none}.vp-sidebar .vp-navbar-items a{font-weight:600}.vp-sidebar .vp-navbar-item{display:block;padding:.5rem 0 .5rem 1.5rem;font-size:1.1em;line-height:1.25rem}.vp-sidebar-mask{position:fixed;top:0;left:0;z-index:9;display:none;width:100vw;height:100vh}.vp-theme-container.no-navbar .vp-sidebar{top:0}@media (max-width: 719px){.vp-theme-container.no-navbar .vp-sidebar{padding-top:0}}.vp-theme-container.no-navbar .vp-page{padding-top:0}.vp-theme-container.no-navbar .theme-default-content h1,.vp-theme-container.no-navbar .theme-default-content h2,.vp-theme-container.no-navbar .theme-default-content h3,.vp-theme-container.no-navbar .theme-default-content h4,.vp-theme-container.no-navbar .theme-default-content h5,.vp-theme-container.no-navbar .theme-default-content h6{margin-top:1.5rem;padding-top:0}.vp-theme-container.no-sidebar .vp-sidebar{display:none}@media (max-width: 719px){.vp-theme-container.no-sidebar .vp-sidebar{display:block}}.vp-theme-container.no-sidebar .vp-page{padding-left:0}@media (max-width: 719px){.vp-theme-container.sidebar-open .vp-sidebar{transform:translate(0)}.vp-theme-container.sidebar-open .vp-sidebar-mask{display:block}}.fade-slide-y-enter-active{transition:all .2s ease}.fade-slide-y-leave-active{transition:all .2s cubic-bezier(1,.5,.8,1)}.fade-slide-y-enter-from,.fade-slide-y-leave-to{opacity:0;transform:translateY(10px)}.vp-theme-container[data-v-463c2c5d]{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width: 959px){.vp-theme-container[data-v-463c2c5d]{padding:2rem}}:root{--vp-c-white: #fff;--vp-c-black: #000;--vp-c-grey-text: #dddde3;--vp-c-grey-hover: #e4e4e9;--vp-c-grey-bg: #ebebef;--vp-c-grey-soft: rgb(142 150 170 / 14%);--vp-c-indigo-text: #3451b2;--vp-c-indigo-hover: #3a5ccc;--vp-c-indigo-bg: #5672cd;--vp-c-indigo-soft: rgb(100 108 255 / 14%);--vp-c-purple-text: #6f42c1;--vp-c-purple-hover: #7e4cc9;--vp-c-purple-bg: #8e5cd9;--vp-c-purple-soft: rgb(159 122 234 / 14%);--vp-c-green-text: #18794e;--vp-c-green-hover: #299764;--vp-c-green-bg: #30a46c;--vp-c-green-soft: rgb(16 185 129 / 14%);--vp-c-yellow-text: #915930;--vp-c-yellow-hover: #946300;--vp-c-yellow-bg: #9f6a00;--vp-c-yellow-soft: rgb(234 179 8 / 14%);--vp-c-red-text: #b8272c;--vp-c-red-hover: #d5393e;--vp-c-red-bg: #e0575b;--vp-c-red-soft: rgb(244 63 94 / 14%)}[data-theme=dark]{--vp-c-white: #000;--vp-c-black: #fff;--vp-c-grey-text: #515c67;--vp-c-grey-hover: #414853;--vp-c-grey-bg: #32363f;--vp-c-grey-soft: rgb(101 117 133 / 16%);--vp-c-indigo-text: #a8b1ff;--vp-c-indigo-hover: #5c73e7;--vp-c-indigo-bg: #3e63dd;--vp-c-indigo-soft: rgb(100 108 255 / 16%);--vp-c-purple-text: #c8abfa;--vp-c-purple-hover: #a879e6;--vp-c-purple-bg: #8e5cd9;--vp-c-purple-soft: rgb(159 122 234 / 16%);--vp-c-green-text: #3dd68c;--vp-c-green-hover: #30a46c;--vp-c-green-bg: #298459;--vp-c-green-soft: rgb(16 185 129 / 16%);--vp-c-yellow-text: #f9b44e;--vp-c-yellow-hover: #da8b17;--vp-c-yellow-bg: #a46a0a;--vp-c-yellow-soft: rgb(234 179 8 / 16%);--vp-c-red-text: #f66f81;--vp-c-red-hover: #f14158;--vp-c-red-bg: #b62a3c;--vp-c-red-soft: rgb(244 63 94 / 16%)}html,body{background:var(--vp-c-bg)}html{font-size:16px;font-display:optional;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-tap-highlight-color:transparent;-webkit-text-size-adjust:none;-moz-text-size-adjust:none;text-size-adjust:none}@media print{html{font-size:12pt}}html[data-theme=dark]{color-scheme:dark}body{min-height:100vh;margin:0;padding:0;color:#2c3e50;font-synthesis:style}a{color:var(--vp-c-accent);font-weight:500;text-decoration:none;overflow-wrap:break-word}kbd{display:inline-block;min-width:1em;margin-inline:.125rem;padding:.25em;border:1px solid #eee;border-radius:.25em;box-shadow:1px 1px 4px 0 var(--vp-c-shadow);line-height:1;letter-spacing:-.1em;text-align:center}:not(pre)>code{margin:0;padding:3px 6px;border-radius:4px;background:#7f7f7f1f;font-size:.875em;overflow-wrap:break-word}table code{padding:.1rem .4rem}p a code{color:var(--vp-c-accent);font-weight:400}strong{font-weight:600}h1,h2,h3,h4,h5,h6{font-weight:600;line-height:1.25;overflow-wrap:break-word}h1:focus-visible,h2:focus-visible,h3:focus-visible,h4:focus-visible,h5:focus-visible,h6:focus-visible{outline:none}h1{font-size:2rem}h2{padding-bottom:.3rem;border-bottom:1px solid #eaecef;font-size:1.65rem}h3{font-size:1.35rem}h4{font-size:1.15rem}h5{font-size:1.05rem}h6{font-size:1rem}a.header-anchor{position:relative;color:inherit;text-decoration:none}a.header-anchor:hover:before{content:"ยถ";position:absolute;top:.4167em;left:-.75em;color:var(--vp-c-accent);font-size:.75em}a.header-anchor:focus-visible{outline:none}a.header-anchor:focus-visible:before{content:"ยถ";position:absolute;left:-.75em;color:var(--vp-c-accent);outline:auto}p,ul,ol{line-height:1.6;overflow-wrap:break-word}@media print{p,ul,ol{line-height:1.5}}ul,ol{padding-inline-start:1.2em}blockquote{margin:1rem 0;padding:.25rem 0 .25rem 1rem;border-inline-start:.2rem solid #ddd;color:#666;font-size:1rem;overflow-wrap:break-word}blockquote>p{margin:0}hr{border:0;border-top:1px solid #eaecef}table{display:block;overflow-x:auto;margin:1rem 0;border-collapse:collapse}tbody tr:nth-child(odd){background:#f6f8fa}th,td{padding:.6em 1em;border:1px solid #dfe2e5}pre{text-align:left;direction:ltr;white-space:pre;word-spacing:normal;word-wrap:normal;word-break:normal;overflow-wrap:unset;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;hyphens:none}@media print{pre{white-space:pre-wrap}}pre code{padding:0;border-radius:0}@page{margin:2cm;font-size:12pt;size:a4}@media print{*,:after,:before{box-shadow:none!important;text-shadow:none!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}a{color:inherit;font-weight:inherit!important;font-size:inherit!important;text-decoration:underline}a.header-anchor{text-decoration:none}abbr[title]:after{content:" (" attr(title) ")"}pre{border:1px solid #eee;white-space:pre-wrap!important}pre>code{white-space:pre-wrap!important}blockquote{border-inline-start:.2rem solid #ddd;color:inherit}blockquote,pre{orphans:5;widows:5}img,tr,canvas{page-break-inside:avoid}}@media (prefers-reduced-motion: reduce){*,:before,:after{background-attachment:initial!important;scroll-behavior:auto!important;transition-delay:0s!important;transition-duration:0s!important;animation-duration:1ms!important;animation-delay:-1ms!important;animation-iteration-count:1!important}}:root{--vp-c-accent: #299764;--vp-c-accent-bg: #3eaf7c;--vp-c-accent-hover: #4abf8a;--vp-c-accent-text: var(--vp-c-white);--vp-c-accent-soft: rgb(16 185 129 / 14%);--vp-c-bg: #fff;--vp-c-bg-alt: #f6f6f7;--vp-c-bg-elv: #fff;--vp-c-text: rgb(60 60 67);--vp-c-text-mute: rgb(60 60 67 / 78%);--vp-c-text-subtle: rgb(60 60 67 / 56%);--vp-c-gutter: #eaecef;--vp-c-border: #d7d9da;--vp-c-border-hard: #d1d4d7;--vp-c-shadow: rgb(0 0 0 / 15%);--vp-c-control: #f9fafb;--vp-c-control-hover: #f1f3f5;--vp-c-control-disabled: #eaeaea;--vp-navbar-c-bg: var(--vp-c-bg);--vp-sidebar-c-bg: var(--vp-c-bg);--vp-c-code-tab-title: var(--code-c-text, rgb(255 255 255 / 90%));--vp-c-code-tab-bg: var(--code-bg-color, var(--code-c-bg));--vp-c-code-tab-active: var(--vp-c-accent);--c-badge-tip: var(--vp-c-green-soft);--c-badge-tip-text: var(--vp-c-green-text);--c-badge-warning: var(--vp-c-yellow-soft);--c-badge-warning-text: var(--vp-c-yellow-text);--c-badge-danger: var(--vp-c-red-soft);--c-badge-danger-text: var(--vp-c-red-text);--font-family: -apple-system, "BlinkMacSystemFont", "Segoe UI", roboto, oxygen, ubuntu, cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;--navbar-height: 3.6rem;--navbar-padding-v: .7rem;--navbar-padding-h: 1.5rem;--sidebar-width: 20rem;--sidebar-width-mobile: calc(var(--sidebar-width) * .82);--content-width: 740px;--homepage-width: 960px;--vp-t-color: .3s ease;--vp-t-transform: .3s ease;--external-link-icon: url("data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' %3E%3Cpath d='M0 0h24v24H0V0z' fill='none' /%3E%3Cpath d='M9 5v2h6.59L4 18.59 5.41 20 17 8.41V15h2V5H9z' /%3E%3C/svg%3E");--external-link-c-icon: var(--vp-c-text-mute)}[data-theme=dark]{--vp-c-accent: #3dd68c;--vp-c-accent-bg: #3aa675;--vp-c-accent-hover: #349469;--vp-c-accent-soft: rgb(16 185 129 / 16%);--vp-c-bg: #1b1b1f;--vp-c-bg-alt: #161618;--vp-c-bg-elv: #202127;--vp-c-text: rgb(235 235 245 / 86%);--vp-c-text-mute: rgb(235 235 245 / 60%);--vp-c-text-subtle: rgb(235 235 245 / 38%);--vp-c-gutter: #373f4c;--vp-c-border: #3e4c5a;--vp-c-border-hard: #405064;--vp-c-shadow: rgb(0 0 0 / 30%);--vp-c-control: #2d3135;--vp-c-control-hover: #303640;--vp-c-control-disabled: #363636}html,body{background-color:var(--vp-c-bg);accent-color:var(--vp-c-accent);transition:background-color var(--vp-t-color)}[data-theme=dark]{color-scheme:dark}body{color:var(--vp-c-text);font-size:1rem;font-family:var(--font-family)}h2{border-color:var(--vp-c-gutter);transition:border-color var(--vp-t-color)}a{color:var(--vp-c-accent)}code{font-family:var(--code-font-family)}:not(pre)>code{background-color:var(--vp-c-grey-soft);color:var(--vp-c-text-mute);transition:background-color var(--vp-t-color)}p a code{color:var(--vp-c-accent)}kbd{border-color:var(--vp-c-border-hard);transition:border-color var(--vp-t-color)}blockquote{border-color:var(--vp-c-border-hard);color:var(--vp-c-text-mute);transition:border-color var(--vp-t-color)}hr{border-color:var(--vp-c-gutter);transition:border-color var(--vp-t-color)}table{transition:border-color var(--vp-t-color)}tbody tr:nth-child(odd){background-color:var(--vp-c-bg-alt);transition:background-color var(--vp-t-color)}th,td{border-color:var(--vp-c-border-hard);transition:border-color var(--vp-t-color)}.theme-default-content h1,.theme-default-content h2,.theme-default-content h3,.theme-default-content h4,.theme-default-content h5,.theme-default-content h6{margin-top:calc(.5rem - var(--navbar-height));margin-bottom:0;padding-top:calc(1rem + var(--navbar-height))}.theme-default-content h1:first-child,.theme-default-content h2:first-child,.theme-default-content h3:first-child,.theme-default-content h4:first-child,.theme-default-content h5:first-child,.theme-default-content h6:first-child{margin-bottom:1rem}.theme-default-content h1:first-child+p,.theme-default-content h1:first-child+pre,.theme-default-content h1:first-child+.custom-container,.theme-default-content h2:first-child+p,.theme-default-content h2:first-child+pre,.theme-default-content h2:first-child+.custom-container,.theme-default-content h3:first-child+p,.theme-default-content h3:first-child+pre,.theme-default-content h3:first-child+.custom-container,.theme-default-content h4:first-child+p,.theme-default-content h4:first-child+pre,.theme-default-content h4:first-child+.custom-container,.theme-default-content h5:first-child+p,.theme-default-content h5:first-child+pre,.theme-default-content h5:first-child+.custom-container,.theme-default-content h6:first-child+p,.theme-default-content h6:first-child+pre,.theme-default-content h6:first-child+.custom-container{margin-top:2rem}@media (max-width: 419px){.theme-default-content h1{font-size:1.9rem}}.theme-default-content a:not(.header-anchor){text-decoration:underline}.theme-default-content img{max-width:100%}div[class*=language-]{margin:.75rem 0;transition:background-color var(--vp-t-color),color var(--vp-t-color)}@media (max-width: 419px){div[class*=language-]{--code-border-radius: 0;margin:.75rem -1.5rem}}div[class*=language-] .line.diff,div[class*=language-] .line.highlighted{transition:background-color var(--vp-t-color)}.table-of-contents .vp-badge{vertical-align:middle}.arrow{display:inline-block;vertical-align:middle;width:1em;height:1em;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(0,0,0,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E");background-position:center;background-repeat:no-repeat;line-height:normal;transition:all .3s}[data-theme=dark] .arrow{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(255,255,255,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E")}.arrow.down{transform:rotate(180deg)}.arrow.right{transform:rotate(90deg)}.arrow.left{transform:rotate(-90deg)}.vp-external-link-icon:after{content:"";display:inline-block;flex-shrink:0;width:11px;height:11px;margin-top:-1px;margin-left:4px;background:var(--external-link-c-icon);-webkit-mask-image:var(--external-link-icon);mask-image:var(--external-link-icon)}.external-link-icon .external-link:after{content:"";display:inline-block;flex-shrink:0;width:11px;height:11px;margin-top:-1px;margin-left:4px;background:var(--external-link-c-icon);-webkit-mask-image:var(--external-link-icon);mask-image:var(--external-link-icon)}.external-link-icon .theme-default-content a[href*="://"]:not(.no-external-link-icon):after,.external-link-icon .theme-default-content a[target=_blank]:not(.no-external-link-icon):after{content:"";display:inline-block;flex-shrink:0;width:11px;height:11px;margin-top:-1px;margin-left:4px;background:var(--external-link-c-icon);-webkit-mask-image:var(--external-link-icon);mask-image:var(--external-link-icon)}@media screen and (max-width: 719px){.vp-hide-mobile{display:none}}.vp-comment{max-width:var(--content-width);margin:0 auto;padding:2rem 2.5rem}@media (max-width: 959px){.vp-comment{padding:2rem}}@media (max-width: 419px){.vp-comment{padding:1.5rem}}.vp-navbar .DocSearch{transition:background-color var(--vp-t-color)}.vp-navbar .search-box{vertical-align:top;flex:0 0 auto}:root{--vp-c-accent: #826aed;--vp-c-accent-bg: #d5ebaa;--c-brand: #99CC33;--c-brand-light: #D7DB0A;--c-text-accent: #826aed;--code-bg-color: #383838;--code-hl-bg-color: rgba(0, 0, 0, .5);--code-ln-color: #fff;--code-ln-wrapper-width: 2rem;--content-width: 850px;--homepage-width: 100%;--c-text-quote: rgb(130, 122, 165);--c-tip: #b5d935 !important;--c-details-bg: rgba(125,125,125,.05);--font-family: "Nunito Sans", sans-serif;--navbar-padding-h: .7rem;--c-border: #eaecef;--c-border-dark: #dfe2e5;--vp-c-gutter: var(--c-border-dark)}:root .navbar-dropdown{box-shadow:0 0 10px #14141433;border-radius:.7em}:root[data-theme=dark]{--c-border: #4b4b4b;--c-border-dark: #525252;--vp-c-accent: #b7aaf0;--c-text-accent: #b7aaf0}html.dark a{color:#a493f1}.sidebar-item-children .sidebar-item-children{opacity:.9;font-size:.92em!important;padding-bottom:.3em;border-left:.3em solid var(--c-text-accent)}.sidebar-item-children a{padding-top:.1em!important;padding-bottom:.1em!important}.sidebar-item-children .sidebar-item-children a:before{content:" ";margin-left:-.7em;color:#0000004d}.theme-container,blockquote{font-size:1.1rem}p,ul,ol{line-height:1.5em}::-moz-selection{color:#000;background:#c9e78c}::selection{color:#000;background:#c9e78c}.search-box{--search-border-color: rgba(138, 125, 189, .5)}img{border-radius:.5em}.tip{border-left-width:.25em!important;padding:.2em .2em .5em 2.4em!important;max-width:700px}details,.custom-container{border-radius:10px!important;border:2px solid rgba(255,255,255,.05)!important;outline:1px solid rgba(0,0,0,.2);box-shadow:inset 0 0 20px #0000000d!important;padding:1em!important;margin:.5em 0!important}details summary{font-weight:700!important}details p{margin-top:.5em}.custom-container p:not(:first){margin:0}.custom-container-title{padding-bottom:.5em}table{box-shadow:inset 0 0 40px #6464641a!important;border-radius:.5em;padding:.5em .5em .5em 1em;min-width:100%}@media screen and (min-width: 1700px){table{min-width:1000px}}@media screen and (min-width: 1900px){table{min-width:1200px}}td{width:20%}td:first-child{min-width:10%}td:last-child{width:30%}th{text-align:left}tr,td,th{border:none!important;padding:.5em 1em .8em 0!important}tr,td,th{background:none!important}tr{border-bottom:1px solid rgba(155,155,155,.2)!important;display:table-row}tr:last-child{border-bottom:none!important}td{vertical-align:top}.sample-code-links{display:flex;margin-top:-15px;top:0;border-radius:0 0 10px 10px;width:calc(100% - .6em);padding:.4em .1em .15em .6em}.vp-navbar{backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);display:flex;padding-left:1.3rem;width:-moz-fit-content;width:fit-content;background-color:#fffc;border-radius:3rem;outline:1px solid rgba(255,255,255,.1);box-shadow:0 2px 15px #02022b33;margin:5px auto}html[data-theme=dark] .vp-navbar{background-color:#0d0d0da6;outline:1px solid rgba(0,0,0,.9)}.vp-navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item .navbar-dropdown-subitem-wrapper .navbar-dropdown-subitem{font-size:inherit}@media screen and (max-width: 719px){.vp-navbar{padding-left:4rem}}.vp-navbar .site-name{font-size:1.5rem;margin-right:20px;opacity:.5;color:#000}.sidebar{scrollbar-color:var(--c-brand) transparent}.vp-navbar-items-wrapper{position:initial}.vp-navbar span a{white-space:nowrap}.vp-navbar-dropdown-wrapper:not(.mobile) .vp-navbar-dropdown{border-radius:12px;scrollbar-width:thin;scrollbar-color:var(--c-brand) transparent;max-height:calc(100vh - 4rem);border:1px solid var(--c-border)}:root .vp-navbar-dropdown{box-shadow:0 1px #1414141a}.theme-container{font-size:1rem}span.DocSearch-Button-Keys,kbd.DocSearch-Button-Key{display:none}span.DocSearch-Button-Placeholder{font-family:Nunito Sans,sans-serif;font-size:.9rem}div.DocSearch-Modal{border-radius:20px}footer.DocSearch-Footer{border-radius:0 0 20px 20px}form.DocSearch-Form{border-radius:9px}@media (min-width: 751px){div#docsearch-container{min-width:initial}}footer.page-meta{font-size:.9em;opacity:.5}.vp-navbar-item>a.external-link .external-link-icon{display:none}.header-anchor:hover:before{content:"#"!important}.theme-default-content a:not(.header-anchor){text-decoration:none}.vp-sidebar-item:not(.vp-sidebar-heading){padding-top:0;padding-bottom:0}.vp-sidebar{scrollbar-color:var(--vp-c-accent-bg) transparent}.theme-default-content a:hover{text-decoration:underline}.vp-navbar-dropdown-subitem{font-size:1em;line-height:1.8em}.vp-page-nav .route-link{border:none}.route-link-active+ul{margin-top:0;margin-bottom:1em}.route-link-active+ul:before{content:"on this page";opacity:.5;text-transform:uppercase;padding-left:2.7em;font-weight:700;font-size:.8em}.vp-sidebar-children .vp-sidebar-children .vp-sidebar-item:not(.vp-sidebar-heading).active{font-weight:700}div[class*=language-]>pre{scrollbar-color:var(--vp-c-accent-bg) transparent;scrollbar-width:thin}div[class*=language-]>pre code{font-size:1em;color:wheat}.twoslash-popup-container{font-size:.8em}.twoslash .twoslash-popup-docs{font-size:14px!important}.twoslash .twoslash-popup-code pre.shiki{margin-left:0;white-space:pre-wrap}.twoslash-popup-container{max-width:700px;white-space:initial;min-width:700px}.twoslash-popup-container pre{white-space:pre-wrap}.twoslash-popup-container .twoslash-popup-docs code{display:inline;color:#2d2d65;margin:0;padding:0}.twoslash-popup-docs-tag{display:flex;flex-direction:row;align-items:flex-start;color:initial}.twoslash-popup-docs.twoslash-popup-docs-tags .twoslash-popup-docs-tag-name,.twoslash-popup-docs.twoslash-popup-docs-tags .twoslash-popup-docs-tag-value{color:#000}.twoslash-popup-docs.twoslash-popup-docs-tags .twoslash-popup-docs-tag-name{font-weight:700;margin-right:.5em;color:#004683}.twoslash-popup-docs-tag-value p{display:inline-block;margin:0;padding:0}.vp-navbar button:hover{cursor:pointer;background:none}.vp-navbar-item>div>button:hover{margin-bottom:-2px;border-bottom:2px solid var(--vp-c-accent)}.vp-navbar-item>a:hover,.vp-navbar-item a.route-link-active{color:var(--vp-c-text)}.vp-page ol{counter-reset:myOrderedListItemsCounter;border-left:1px solid rgba(128,128,128,.3803921569);margin-left:30px;padding-left:31px;position:relative}.vp-page ol:before{position:absolute;left:-4.5px;bottom:0;width:8px;height:8px;background:#d9d9d9;content:"";border-radius:10px}.vp-page ol>li{list-style-type:none;position:relative;margin-bottom:1.5em;margin-left:0}.vp-page ol>li:before{counter-increment:myOrderedListItemsCounter;content:counter(myOrderedListItemsCounter) "";margin-right:.5em;background:var(--vp-c-border);border-radius:3em;width:30px;height:30px;display:inline-block;text-align:center;border:1px solid #6d51e1;line-height:1.8em;position:absolute;left:-50px;top:-4px;border:4px solid var(--vp-c-bg)}.vp-page ol>li>p{display:inline}.vp-sidebar-items ul{line-height:1.85em}.vp-sidebar-children .vp-sidebar-children .vp-sidebar-item:not(.vp-sidebar-heading){padding-top:0;padding-bottom:0}.vp-sidebar-item:not(.vp-sidebar-heading)+.vp-sidebar-children{line-height:1.65em}div.code-group-item.active:has(iframe){margin-top:30px}.hint-container p{padding-right:2rem}.vp-site-name{display:none}.vp-navbar-item>div>button:hover{border-radius:0}/*! @docsearch/css 3.6.1 | MIT License | ยฉ Algolia, Inc. and contributors | https://docsearch.algolia.com */:root{--docsearch-primary-color:#5468ff;--docsearch-text-color:#1c1e21;--docsearch-spacing:12px;--docsearch-icon-stroke-width:1.4;--docsearch-highlight-color:var(--docsearch-primary-color);--docsearch-muted-color:#969faf;--docsearch-container-background:rgba(101,108,133,.8);--docsearch-logo-color:#5468ff;--docsearch-modal-width:560px;--docsearch-modal-height:600px;--docsearch-modal-background:#f5f6f7;--docsearch-modal-shadow:inset 1px 1px 0 0 hsla(0,0%,100%,.5),0 3px 8px 0 #555a64;--docsearch-searchbox-height:56px;--docsearch-searchbox-background:#ebedf0;--docsearch-searchbox-focus-background:#fff;--docsearch-searchbox-shadow:inset 0 0 0 2px var(--docsearch-primary-color);--docsearch-hit-height:56px;--docsearch-hit-color:#444950;--docsearch-hit-active-color:#fff;--docsearch-hit-background:#fff;--docsearch-hit-shadow:0 1px 3px 0 #d4d9e1;--docsearch-key-gradient:linear-gradient(-225deg,#d5dbe4,#f8f8f8);--docsearch-key-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 2px 1px rgba(30,35,90,.4);--docsearch-key-pressed-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 1px 0 rgba(30,35,90,.4);--docsearch-footer-height:44px;--docsearch-footer-background:#fff;--docsearch-footer-shadow:0 -1px 0 0 #e0e3e8,0 -3px 6px 0 rgba(69,98,155,.12)}html[data-theme=dark]{--docsearch-text-color:#f5f6f7;--docsearch-container-background:rgba(9,10,17,.8);--docsearch-modal-background:#15172a;--docsearch-modal-shadow:inset 1px 1px 0 0 #2c2e40,0 3px 8px 0 #000309;--docsearch-searchbox-background:#090a11;--docsearch-searchbox-focus-background:#000;--docsearch-hit-color:#bec3c9;--docsearch-hit-shadow:none;--docsearch-hit-background:#090a11;--docsearch-key-gradient:linear-gradient(-26.5deg,#565872,#31355b);--docsearch-key-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 2px 2px 0 rgba(3,4,9,.3);--docsearch-key-pressed-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 1px 1px 0 rgba(3,4,9,.30196078431372547);--docsearch-footer-background:#1e2136;--docsearch-footer-shadow:inset 0 1px 0 0 rgba(73,76,106,.5),0 -4px 8px 0 rgba(0,0,0,.2);--docsearch-logo-color:#fff;--docsearch-muted-color:#7f8497}.DocSearch-Button{align-items:center;background:var(--docsearch-searchbox-background);border:0;border-radius:40px;color:var(--docsearch-muted-color);cursor:pointer;display:flex;font-weight:500;height:36px;justify-content:space-between;margin:0 0 0 16px;padding:0 8px;-webkit-user-select:none;-moz-user-select:none;user-select:none}.DocSearch-Button:active,.DocSearch-Button:focus,.DocSearch-Button:hover{background:var(--docsearch-searchbox-focus-background);box-shadow:var(--docsearch-searchbox-shadow);color:var(--docsearch-text-color);outline:none}.DocSearch-Button-Container{align-items:center;display:flex}.DocSearch-Search-Icon{stroke-width:1.6}.DocSearch-Button .DocSearch-Search-Icon{color:var(--docsearch-text-color)}.DocSearch-Button-Placeholder{font-size:1rem;padding:0 12px 0 6px}.DocSearch-Button-Keys{display:flex;min-width:calc(40px + .8em)}.DocSearch-Button-Key{align-items:center;background:var(--docsearch-key-gradient);border-radius:3px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);display:flex;height:18px;justify-content:center;margin-right:.4em;position:relative;padding:0 0 2px;border:0;top:-1px;width:20px}.DocSearch-Button-Key--pressed{transform:translate3d(0,1px,0);box-shadow:var(--docsearch-key-pressed-shadow)}@media (max-width:768px){.DocSearch-Button-Keys,.DocSearch-Button-Placeholder{display:none}}.DocSearch--active{overflow:hidden!important}.DocSearch-Container,.DocSearch-Container *{box-sizing:border-box}.DocSearch-Container{background-color:var(--docsearch-container-background);height:100vh;left:0;position:fixed;top:0;width:100vw;z-index:200}.DocSearch-Container a{text-decoration:none}.DocSearch-Link{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;font:inherit;margin:0;padding:0}.DocSearch-Modal{background:var(--docsearch-modal-background);border-radius:6px;box-shadow:var(--docsearch-modal-shadow);flex-direction:column;margin:60px auto auto;max-width:var(--docsearch-modal-width);position:relative}.DocSearch-SearchBar{display:flex;padding:var(--docsearch-spacing) var(--docsearch-spacing) 0}.DocSearch-Form{align-items:center;background:var(--docsearch-searchbox-focus-background);border-radius:4px;box-shadow:var(--docsearch-searchbox-shadow);display:flex;height:var(--docsearch-searchbox-height);margin:0;padding:0 var(--docsearch-spacing);position:relative;width:100%}.DocSearch-Input{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:0;color:var(--docsearch-text-color);flex:1;font:inherit;font-size:1.2em;height:100%;outline:none;padding:0 0 0 8px;width:80%}.DocSearch-Input::-moz-placeholder{color:var(--docsearch-muted-color);opacity:1}.DocSearch-Input::placeholder{color:var(--docsearch-muted-color);opacity:1}.DocSearch-Input::-webkit-search-cancel-button,.DocSearch-Input::-webkit-search-decoration,.DocSearch-Input::-webkit-search-results-button,.DocSearch-Input::-webkit-search-results-decoration{display:none}.DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset{margin:0;padding:0}.DocSearch-MagnifierLabel,.DocSearch-Reset{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}.DocSearch-Container--Stalled .DocSearch-MagnifierLabel,.DocSearch-LoadingIndicator{display:none}.DocSearch-Container--Stalled .DocSearch-LoadingIndicator{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Reset{animation:none;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;right:0;stroke-width:var(--docsearch-icon-stroke-width)}}.DocSearch-Reset{animation:fade-in .1s ease-in forwards;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;padding:2px;right:0;stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Reset[hidden]{display:none}.DocSearch-Reset:hover{color:var(--docsearch-highlight-color)}.DocSearch-LoadingIndicator svg,.DocSearch-MagnifierLabel svg{height:24px;width:24px}.DocSearch-Cancel{display:none}.DocSearch-Dropdown{max-height:calc(var(--docsearch-modal-height) - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height));min-height:var(--docsearch-spacing);overflow-y:auto;overflow-y:overlay;padding:0 var(--docsearch-spacing);scrollbar-color:var(--docsearch-muted-color) var(--docsearch-modal-background);scrollbar-width:thin}.DocSearch-Dropdown::-webkit-scrollbar{width:12px}.DocSearch-Dropdown::-webkit-scrollbar-track{background:transparent}.DocSearch-Dropdown::-webkit-scrollbar-thumb{background-color:var(--docsearch-muted-color);border:3px solid var(--docsearch-modal-background);border-radius:20px}.DocSearch-Dropdown ul{list-style:none;margin:0;padding:0}.DocSearch-Label{font-size:.75em;line-height:1.6em}.DocSearch-Help,.DocSearch-Label{color:var(--docsearch-muted-color)}.DocSearch-Help{font-size:.9em;margin:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.DocSearch-Title{font-size:1.2em}.DocSearch-Logo a{display:flex}.DocSearch-Logo svg{color:var(--docsearch-logo-color);margin-left:8px}.DocSearch-Hits:last-of-type{margin-bottom:24px}.DocSearch-Hits mark{background:none;color:var(--docsearch-highlight-color)}.DocSearch-HitsFooter{color:var(--docsearch-muted-color);display:flex;font-size:.85em;justify-content:center;margin-bottom:var(--docsearch-spacing);padding:var(--docsearch-spacing)}.DocSearch-HitsFooter a{border-bottom:1px solid;color:inherit}.DocSearch-Hit{border-radius:4px;display:flex;padding-bottom:4px;position:relative}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit--deleting{transition:none}}.DocSearch-Hit--deleting{opacity:0;transition:all .25s linear}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit--favoriting{transition:none}}.DocSearch-Hit--favoriting{transform:scale(0);transform-origin:top center;transition:all .25s linear;transition-delay:.25s}.DocSearch-Hit a{background:var(--docsearch-hit-background);border-radius:4px;box-shadow:var(--docsearch-hit-shadow);display:block;padding-left:var(--docsearch-spacing);width:100%}.DocSearch-Hit-source{background:var(--docsearch-modal-background);color:var(--docsearch-highlight-color);font-size:.85em;font-weight:600;line-height:32px;margin:0 -4px;padding:8px 4px 0;position:sticky;top:0;z-index:10}.DocSearch-Hit-Tree{color:var(--docsearch-muted-color);height:var(--docsearch-hit-height);opacity:.5;stroke-width:var(--docsearch-icon-stroke-width);width:24px}.DocSearch-Hit[aria-selected=true] a{background-color:var(--docsearch-highlight-color)}.DocSearch-Hit[aria-selected=true] mark{text-decoration:underline}.DocSearch-Hit-Container{align-items:center;color:var(--docsearch-hit-color);display:flex;flex-direction:row;height:var(--docsearch-hit-height);padding:0 var(--docsearch-spacing) 0 0}.DocSearch-Hit-icon{height:20px;width:20px}.DocSearch-Hit-action,.DocSearch-Hit-icon{color:var(--docsearch-muted-color);stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Hit-action{align-items:center;display:flex;height:22px;width:22px}.DocSearch-Hit-action svg{display:block;height:18px;width:18px}.DocSearch-Hit-action+.DocSearch-Hit-action{margin-left:6px}.DocSearch-Hit-action-button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:inherit;cursor:pointer;padding:2px}svg.DocSearch-Hit-Select-Icon{display:none}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Select-Icon{display:block}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:background-color .1s ease-in}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{transition:none}}.DocSearch-Hit-action-button:focus path,.DocSearch-Hit-action-button:hover path{fill:#fff}.DocSearch-Hit-content-wrapper{display:flex;flex:1 1 auto;flex-direction:column;font-weight:500;justify-content:center;line-height:1.2em;margin:0 8px;overflow-x:hidden;position:relative;text-overflow:ellipsis;white-space:nowrap;width:80%}.DocSearch-Hit-title{font-size:.9em}.DocSearch-Hit-path{color:var(--docsearch-muted-color);font-size:.75em}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-action,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-icon,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-path,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-text,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-title,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Tree,.DocSearch-Hit[aria-selected=true] mark{color:var(--docsearch-hit-active-color)!important}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:none}}.DocSearch-ErrorScreen,.DocSearch-NoResults,.DocSearch-StartScreen{font-size:.9em;margin:0 auto;padding:36px 0;text-align:center;width:80%}.DocSearch-Screen-Icon{color:var(--docsearch-muted-color);padding-bottom:12px}.DocSearch-NoResults-Prefill-List{display:inline-block;padding-bottom:24px;text-align:left}.DocSearch-NoResults-Prefill-List ul{display:inline-block;padding:8px 0 0}.DocSearch-NoResults-Prefill-List li{list-style-position:inside;list-style-type:"ยป "}.DocSearch-Prefill{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:1em;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;font-size:1em;font-weight:700;padding:0}.DocSearch-Prefill:focus,.DocSearch-Prefill:hover{outline:none;text-decoration:underline}.DocSearch-Footer{align-items:center;background:var(--docsearch-footer-background);border-radius:0 0 8px 8px;box-shadow:var(--docsearch-footer-shadow);display:flex;flex-direction:row-reverse;flex-shrink:0;height:var(--docsearch-footer-height);justify-content:space-between;padding:0 var(--docsearch-spacing);position:relative;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%;z-index:300}.DocSearch-Commands{color:var(--docsearch-muted-color);display:flex;list-style:none;margin:0;padding:0}.DocSearch-Commands li{align-items:center;display:flex}.DocSearch-Commands li:not(:last-of-type){margin-right:.8em}.DocSearch-Commands-Key{align-items:center;background:var(--docsearch-key-gradient);border-radius:2px;box-shadow:var(--docsearch-key-shadow);display:flex;height:18px;justify-content:center;margin-right:.4em;padding:0 0 1px;color:var(--docsearch-muted-color);border:0;width:20px}.DocSearch-VisuallyHiddenForAccessibility{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}@media (max-width:768px){:root{--docsearch-spacing:10px;--docsearch-footer-height:40px}.DocSearch-Dropdown{height:100%}.DocSearch-Container{height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh, 1vh)*100);position:absolute}.DocSearch-Footer{border-radius:0;bottom:0;position:absolute}.DocSearch-Hit-content-wrapper{display:flex;position:relative;width:80%}.DocSearch-Modal{border-radius:0;box-shadow:none;height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh, 1vh)*100);margin:0;max-width:100%;width:100%}.DocSearch-Dropdown{max-height:calc(var(--docsearch-vh, 1vh)*100 - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height))}.DocSearch-Cancel{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;flex:none;font:inherit;font-size:1em;font-weight:500;margin-left:var(--docsearch-spacing);outline:none;overflow:hidden;padding:0;-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap}.DocSearch-Commands,.DocSearch-Hit-Tree{display:none}}@keyframes fade-in{0%{opacity:0}to{opacity:1}}@media (max-width: 750px){.DocSearch-Container{position:fixed}}@media print{#docsearch-container,.DocSearch-Button{display:none}}:root,html[data-theme=dark]{--docsearch-primary-color: var(--vp-c-accent);--docsearch-text-color: var(--vp-c-text);--docsearch-highlight-color: var(--vp-c-accent);--docsearch-muted-color: var(--vp-c-text-mute);--docsearch-container-background: rgb(16 16 16 / 75%);--docsearch-modal-background: var(--vp-c-bg-elv);--docsearch-searchbox-background: var(--vp-c-grey-soft);--docsearch-searchbox-focus-background: var(--vp-c-bg);--docsearch-searchbox-shadow: inset 0 0 0 2px var(--vp-c-accent-soft);--docsearch-hit-color: var(--vp-c-text-mute);--docsearch-hit-active-color: var(--vp-c-bg);--docsearch-hit-background: var(--vp-c-bg);--docsearch-hit-shadow: 0 1px 3px 0 var(--vp-c-border-hard);--docsearch-footer-background: var(--vp-c-bg)}html[data-theme=dark]{--docsearch-modal-shadow: inset 1px 1px 0 0 #2c2e40, 0 3px 8px 0 #000309;--docsearch-key-shadow: inset 0 -2px 0 0 #282d55, inset 0 0 1px 1px #51577d, 0 2px 2px 0 rgb(3 4 9 / 30%);--docsearch-key-gradient: linear-gradient(-225deg, #444950, #1c1e21);--docsearch-footer-shadow: inset 0 1px 0 0 rgb(73 76 106 / 50%), 0 -4px 8px 0 rgb(0 0 0 / 20%)}:root{--code-padding-x: 1.25rem;--code-padding-y: 1rem;--code-border-radius: 6px;--code-line-height: 1.6;--code-font-family: consolas, monaco, "Andale Mono", "Ubuntu Mono", monospace}div[class*=language-]{position:relative;border-radius:var(--code-border-radius);background-color:var(--code-c-bg)}div[class*=language-]:before{content:attr(data-title);position:absolute;top:.8em;right:1em;z-index:3;color:var(--code-c-text);font-size:.75rem}div[class*=language-] pre{position:relative;z-index:1;overflow-x:auto;margin:.75rem 0;border-radius:var(--code-border-radius);font-size:14px;font-family:var(--code-font-family);line-height:var(--code-line-height)}div[class*=language-] pre code{display:block;box-sizing:border-box;width:-moz-fit-content;width:fit-content;min-width:100%;padding:var(--code-padding-y) var(--code-padding-x);background-color:transparent!important;overflow-wrap:unset;-webkit-font-smoothing:auto;-moz-osx-font-smoothing:auto}:root{--code-c-text: #9e9e9e;--code-c-highlight-bg: rgba(142 150 170 / 14%)}.shiki span{color:var(--shiki-light, inherit)}[data-theme=dark] .shiki span{color:var(--shiki-dark, inherit)}div[data-highlighter=shiki]{background-color:var(--code-c-bg, var(--shiki-light-bg))}[data-theme=dark] div[data-highlighter=shiki]{background-color:var(--code-c-bg, var(--shiki-dark-bg))}:root{--code-line-number-width: 3rem}div[class*=language-]:not(.line-numbers-mode) .line-numbers{display:none}div[class*=language-].line-numbers-mode:after{content:"";position:absolute;top:0;left:0;width:var(--code-line-number-width);height:100%;border-right:1px solid var(--code-c-highlight-bg, var(--code-c-text));border-radius:var(--code-border-radius) 0 0 var(--code-border-radius);transition:border var(--t-color)}div[class*=language-].line-numbers-mode pre{vertical-align:middle;margin-left:var(--code-line-number-width)}div[class*=language-].line-numbers-mode code{padding-left:1rem}div[class*=language-].line-numbers-mode .line-numbers{counter-reset:line-number;position:absolute;top:0;width:var(--code-line-number-width);padding-top:var(--code-padding-y);color:var(--code-c-line-number, var(--code-c-text));font-size:.875em;line-height:var(--code-line-height);text-align:center}div[class*=language-].line-numbers-mode .line-number{position:relative;z-index:3;font-family:var(--code-font-family);-webkit-user-select:none;-moz-user-select:none;user-select:none}div[class*=language-].line-numbers-mode .line-number:before{content:counter(line-number);counter-increment:line-number}:root{--twoslash-border-color: #8888;--twoslash-underline-color: currentColor;--twoslash-highlighted-border: #c37d0d50;--twoslash-highlighted-bg: #c37d0d20;--twoslash-popup-bg: #f8f8f8;--twoslash-popup-color: inherit;--twoslash-popup-shadow: rgba(0, 0, 0, .08) 0px 1px 4px;--twoslash-docs-color: #888;--twoslash-docs-font: sans-serif;--twoslash-code-font: inherit;--twoslash-code-font-size: 1em;--twoslash-matched-color: inherit;--twoslash-unmatched-color: #888;--twoslash-cursor-color: #8888;--twoslash-error-color: #d45656;--twoslash-error-bg: #d4565620;--twoslash-warn-color: #c37d0d;--twoslash-warn-bg: #c37d0d20;--twoslash-tag-color: #3772cf;--twoslash-tag-bg: #3772cf20;--twoslash-tag-warn-color: var(--twoslash-warn-color);--twoslash-tag-warn-bg: var(--twoslash-warn-bg);--twoslash-tag-annotate-color: #1ba673;--twoslash-tag-annotate-bg: #1ba67320}@media (prefers-reduced-motion: reduce){.twoslash *{transition:none!important}}.twoslash:hover .twoslash-hover{border-color:var(--twoslash-underline-color)}.twoslash .twoslash-hover{border-bottom:1px dotted transparent;transition-timing-function:ease;transition:border-color .3s;position:relative}.twoslash .twoslash-popup-container{position:absolute;opacity:0;display:inline-flex;flex-direction:column;transform:translateY(1.1em);background:var(--twoslash-popup-bg);color:var(--twoslash-popup-color);border:1px solid var(--twoslash-border-color);transition:opacity .3s;border-radius:4px;pointer-events:none;z-index:10;-webkit-user-select:none;-moz-user-select:none;user-select:none;text-align:left;box-shadow:var(--twoslash-popup-shadow)}.twoslash .twoslash-query-presisted .twoslash-popup-container{z-index:9;transform:translateY(1.5em)}.twoslash .twoslash-hover:hover .twoslash-popup-container,.twoslash .twoslash-error-hover:hover .twoslash-popup-container,.twoslash .twoslash-query-presisted .twoslash-popup-container,.twoslash .twoslash-query-line .twoslash-popup-container{opacity:1;pointer-events:auto}.twoslash .twoslash-popup-container:hover{-webkit-user-select:auto;-moz-user-select:auto;user-select:auto}.twoslash .twoslash-popup-arrow{position:absolute;top:-4px;left:1em;border-top:1px solid var(--twoslash-border-color);border-right:1px solid var(--twoslash-border-color);background:var(--twoslash-popup-bg);transform:rotate(-45deg);width:6px;height:6px;pointer-events:none}.twoslash .twoslash-popup-code,.twoslash .twoslash-popup-error,.twoslash .twoslash-popup-docs{padding:6px 8px!important}.twoslash .twoslash-popup-code{font-family:var(--twoslash-code-font);font-size:var(--twoslash-code-font-size)}.twoslash .twoslash-popup-docs{color:var(--twoslash-docs-color);font-family:var(--twoslash-docs-font);font-size:.8em;border-top:1px solid var(--twoslash-border-color)}.twoslash .twoslash-popup-error{color:var(--twoslash-error-color);background-color:var(--twoslash-error-bg);font-family:var(--twoslash-docs-font);font-size:.8em}.twoslash .twoslash-popup-docs-tags{display:flex;flex-direction:column;font-family:var(--twoslash-docs-font)}.twoslash .twoslash-popup-docs-tags,.twoslash .twoslash-popup-docs-tag-name{margin-right:.5em}.twoslash .twoslash-popup-docs-tag-name{font-family:var(--twoslash-code-font)}.twoslash .twoslash-query-line .twoslash-popup-container{position:relative;margin-bottom:1.4em;transform:translateY(.6em)}.twoslash .twoslash-error-line{position:relative;background-color:var(--twoslash-error-bg);border-left:3px solid var(--twoslash-error-color);color:var(--twoslash-error-color);padding:6px 12px;margin:.2em 0;min-width:100%;width:-moz-max-content;width:max-content}.twoslash .twoslash-error-line.twoslash-error-level-warning{background-color:var(--twoslash-warn-bg);border-left:3px solid var(--twoslash-warn-color);color:var(--twoslash-warn-color)}.twoslash .twoslash-error{background:url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%206%203'%20enable-background%3D'new%200%200%206%203'%20height%3D'3'%20width%3D'6'%3E%3Cg%20fill%3D'%23c94824'%3E%3Cpolygon%20points%3D'5.5%2C0%202.5%2C3%201.1%2C3%204.1%2C0'%2F%3E%3Cpolygon%20points%3D'4%2C0%206%2C2%206%2C0.6%205.4%2C0'%2F%3E%3Cpolygon%20points%3D'0%2C2%201%2C3%202.4%2C3%200%2C0.6'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E") repeat-x bottom left;padding-bottom:2px}.twoslash .twoslash-error.twoslash-error-level-warning{background:url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%206%203'%20enable-background%3D'new%200%200%206%203'%20height%3D'3'%20width%3D'6'%3E%3Cg%20fill%3D'%23c37d0d'%3E%3Cpolygon%20points%3D'5.5%2C0%202.5%2C3%201.1%2C3%204.1%2C0'%2F%3E%3Cpolygon%20points%3D'4%2C0%206%2C2%206%2C0.6%205.4%2C0'%2F%3E%3Cpolygon%20points%3D'0%2C2%201%2C3%202.4%2C3%200%2C0.6'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E") repeat-x bottom left;padding-bottom:2px}.twoslash .twoslash-completion-cursor{position:relative}.twoslash .twoslash-completion-cursor .twoslash-completion-list{-webkit-user-select:none;-moz-user-select:none;user-select:none;position:absolute;top:0;left:0;transform:translateY(1.2em);margin:3px 0 0 -1px;display:inline-block;z-index:8;box-shadow:var(--twoslash-popup-shadow);background:var(--twoslash-popup-bg);border:1px solid var(--twoslash-border-color)}.twoslash-completion-list{width:240px;font-size:.8rem;padding:4px;display:flex;flex-direction:column;gap:4px}.twoslash-completion-list:hover{-webkit-user-select:auto;-moz-user-select:auto;user-select:auto}.twoslash-completion-list:before{background-color:var(--twoslash-cursor-color);width:2px;position:absolute;top:-1.6em;height:1.4em;left:-1px;content:" "}.twoslash-completion-list li{overflow:hidden;display:flex;align-items:center;gap:.25em;line-height:1em}.twoslash-completion-list li span.twoslash-completions-unmatched{color:var(--twoslash-unmatched-color)}.twoslash-completion-list .deprecated{text-decoration:line-through;opacity:.5}.twoslash-completion-list li span.twoslash-completions-matched{color:var(--twoslash-matched-color)}.twoslash-highlighted{background-color:var(--twoslash-highlighted-bg);border:1px solid var(--twoslash-highlighted-border);padding:1px 2px;margin:-1px -3px;border-radius:4px}.twoslash-completion-list .twoslash-completions-icon{color:var(--twoslash-unmatched-color);width:1em;flex:none}.twoslash .twoslash-tag-line{position:relative;background-color:var(--twoslash-tag-bg);border-left:3px solid var(--twoslash-tag-color);color:var(--twoslash-tag-color);padding:6px 10px;margin:.2em 0;display:flex;align-items:center;gap:.3em;min-width:100%;width:-moz-max-content;width:max-content}.twoslash .twoslash-tag-line .twoslash-tag-icon{width:1.1em;color:inherit}.twoslash .twoslash-tag-line.twoslash-tag-error-line{background-color:var(--twoslash-error-bg);border-left:3px solid var(--twoslash-error-color);color:var(--twoslash-error-color)}.twoslash .twoslash-tag-line.twoslash-tag-warn-line{background-color:var(--twoslash-tag-warn-bg);border-left:3px solid var(--twoslash-tag-warn-color);color:var(--twoslash-tag-warn-color)}.twoslash .twoslash-tag-line.twoslash-tag-annotate-line{background-color:var(--twoslash-tag-annotate-bg);border-left:3px solid var(--twoslash-tag-annotate-color);color:var(--twoslash-tag-annotate-color)}.action[data-v-705b9710]{display:flex;flex-direction:column;justify-content:center;align-items:center;background:#7d7d7d1a;color:inherit;padding:1em 1em 1.2em;border-radius:1em;margin:.5em;box-shadow:0 0 .5em #64646433,inset 0 0 1.5em #6464641a;border:1px solid rgba(100,100,100,.3);font-size:1.2em;height:30px;transition:all .1s ease-in-out}a[data-v-705b9710]:hover{text-decoration:none}.action[data-v-705b9710]:hover{transition:all .1s ease-in-out;box-shadow:0 0 .3em #ffff6480,inset 0 0 1.5em #c8c8641a}.subtitle[data-v-705b9710]{font-size:.8rem}.actiongroup{display:flex;align-items:center;justify-content:center;flex-wrap:wrap}.actiongroup>*{margin:0 .5em}.contribution[data-v-543822ed]{margin-bottom:10px}.header[data-v-543822ed]{display:flex;align-items:center;justify-content:space-between;border-radius:1em;padding-right:1em;-webkit-user-select:none;-moz-user-select:none;user-select:none}.header.gradient[data-v-543822ed]{background:linear-gradient(180deg,#6464c800,#6464c81a 3%,#c8c8c800)}.profile[data-v-543822ed]{display:flex;align-items:center;margin-bottom:1em;margin-left:.9em;margin-top:1em}.profile img[data-v-543822ed]{width:50px;height:50px;margin-right:10px;border-radius:50%;border:2px solid #ccc;pointer-events:none}.profile .authorname[data-v-543822ed]{font-size:1.2rem;font-weight:600;color:#000;text-decoration:none}html.dark .authorname[data-v-543822ed]{color:#fff}.entry[data-v-bcc3d6f6]{display:block;padding:.2em .2em .3em 1em;border-radius:.7em;font-size:1.4em;font-weight:400}.entry[data-v-bcc3d6f6]:hover{text-decoration:none;background-color:#6464de33;box-shadow:inset 0 0 50px #fff}html.dark .entry[data-v-bcc3d6f6]:hover{box-shadow:inset 0 0 30px #323232}a[data-v-f801cb6e]{color:initial;text-decoration:none}.preview[data-v-f801cb6e]{margin:1%;display:inline-block;position:relative;min-width:48%;flex-grow:1;flex-shrink:1;height:300px;overflow:hidden;-webkit-user-select:none;-moz-user-select:none;user-select:none;border-radius:.5em;box-shadow:0 0 1px #00006433;border:1px solid rgba(0,0,100,.3);transition:all .1s ease-in-out}.preview[data-v-f801cb6e]:hover{cursor:pointer;box-shadow:0 0 10px #0000641a;transition:all .1s ease-in-out}.content[data-v-f801cb6e]{overflow:hidden;bottom:10px;padding:0 10px;position:relative}.title[data-v-f801cb6e]{display:flex;align-items:center;font-size:1.5em;margin:0;padding:1em;height:3em;background:linear-gradient(180deg,#6464c833 20%,#c8c8c800);-webkit-user-select:initial!important;-moz-user-select:initial!important;user-select:initial!important}.overview-link{display:block;padding-top:1em;padding-bottom:1em;text-decoration:none}.overview-link:hover{text-decoration:none}.previews{display:flex;flex-direction:row;flex-wrap:wrap}.footer{margin-top:1em;display:block;padding-top:1em;border-top:1px solid rgba(100,100,100,.2)}.list{display:flex;flex-direction:column}.list>*{width:95%;margin-bottom:10px;border:1px solid rgba(100,100,200,.2);border-radius:.5em;padding:.5em .5em 2em;background:linear-gradient(180deg,#6464c81a,#c8c8c81a 50%)}html.dark .list>*{border:1px solid rgba(200,200,200,.05);background:linear-gradient(180deg,#6464c81a,#64646433 50%)}.footer[data-v-66df4b0b]{display:flex;width:100%;justify-content:center;align-items:center;padding:1em;font-size:.8em;opacity:.8}a[data-v-66df4b0b]{color:inherit;font-weight:400;margin-left:5px}button[data-v-9b3341da]{border:none;border-radius:10em;text-shadow:none;padding:1em 2em;background-color:var(--5058ae9e);transition:background-color .2s ease-in-out;cursor:pointer;margin:.2em .2em .2em -.3em;color:#fff;font-size:var(--b1e81df0)}button[data-v-9b3341da]:hover{background-color:#6248be;background-color:var(--03a7f81f);transition:background-color .2s ease-in-out}a[data-v-9b3341da]{text-shadow:none!important}.quotes[data-v-96af3692]{align-items:center;justify-content:center;flex-wrap:wrap;padding:0 .5em .5em;text-align:center;min-height:90px;display:none}@media (max-width: 768px){.quotes[data-v-96af3692]{min-height:200px}}.quotes[data-v-96af3692]{font-size:1.2em;font-style:italic}div[data-v-b3cc3f9a]{margin-top:.3em;display:flex;flex-direction:column}iframe[data-v-b3cc3f9a]{width:100%;height:100%;border:0;aspect-ratio:16/9}iframe[data-v-b3cc3f9a]:only-of-type{border-radius:1em}iframe[data-v-b3cc3f9a]:first-of-type{border-top-left-radius:1em;border-top-right-radius:1em;margin-bottom:.1em}iframe[data-v-b3cc3f9a]:last-of-type{border-bottom-left-radius:1em;border-bottom-right-radius:1em;margin-top:.1em}@media (max-aspect-ratio: 1/1){iframe[data-v-b3cc3f9a]{aspect-ratio:9/9}}@media (max-aspect-ratio: 9/16){iframe[data-v-b3cc3f9a]{aspect-ratio:9/14}}button{background-color:#1374ef;border:none;color:#fff;padding:.3em;border-radius:.5em;margin-top:.5em}button:hover{background-color:#277ee9;cursor:pointer}.code{display:none}.root[data-v-47fef520]{display:flex}.testimonial[data-v-47fef520]{display:inline-block;margin:0 0 1rem;padding:1rem;background-color:#7d7d7d1a;border-radius:1em;border:1px solid rgba(125,125,125,.2);box-shadow:inset 0 0 10px #7d7d7d1a}.marker[data-v-47fef520]{position:absolute;font-size:2rem;color:#32323280;margin:-1.2rem -.7rem}img[data-v-c9f16638]{height:110px;max-height:70px;aspect-ratio:1/1;-o-object-fit:contain;object-fit:contain;pointer-events:none}img.hidden[data-v-c9f16638]{visibility:hidden}div.tile[data-v-c9f16638]{background:var(--b811b9c2);border:var(--e2940f36) solid var(--7e5aa0ea);border-radius:1em;box-shadow:0 0 5px 1px #0000001a;outline:1px solid var(--c-border);display:flex;flex-direction:column;max-width:230px;min-width:200px;padding:1em;margin-right:1em;margin-top:1em;position:relative;align-items:center;justify-content:space-between;flex-wrap:nowrap}div.small[data-v-c9f16638]{height:220px}div.small .description[data-v-c9f16638]{margin-bottom:.5em}div[data-v-c9f16638]:last-child:not(.small){margin-right:0}h3[data-v-c9f16638]{font-weight:700;margin-top:.5em;padding-top:0}p[data-v-c9f16638]{margin:0;padding:0}p.description[data-v-c9f16638]{font-size:.8em;height:75px;margin-top:.5em;text-align:center}div[data-v-90f1465a]{display:flex;justify-content:flex-start;flex-direction:row;flex-wrap:wrap;align-items:flex-start}div.vertical[data-v-90f1465a]{display:flex;flex-direction:column;justify-content:space-around;align-items:center}.container[data-v-977b38fe]{max-width:100%;aspect-ratio:16/9;max-height:300px}video[data-v-977b38fe],#ytplayer[data-v-977b38fe]{background:#0003;display:block;width:var(--50c06be4);height:var(--22327078);max-width:100%;max-height:100%;margin:.75em 0;max-height:var(--6af71086);aspect-ratio:16/9}#ytplayer[data-v-977b38fe]{aspect-ratio:16/9;border-radius:1em}@media screen and (max-width: 1200px){.container[data-v-977b38fe]{width:100%;height:auto}video[data-v-977b38fe],#ytplayer[data-v-977b38fe]{width:100%;height:auto}} diff --git a/assets/support.html-g_P1G7eN.js b/assets/support.html-g_P1G7eN.js new file mode 100644 index 000000000..486ff0b04 --- /dev/null +++ b/assets/support.html-g_P1G7eN.js @@ -0,0 +1 @@ +import{_ as r,r as s,o as i,c as d,e as l,b as o,a as t,d as a}from"./app-CRZRGfEE.js";const p={};function h(c,e){const n=s("video-embed");return i(),d("div",null,[e[0]||(e[0]=l('

    Support and Community

    Forum

    Ask questions and provide feedback in Needle Forum

    Get instant help with Needle AI

    Ask any question about Needle Engine, web development or our editor integrations and get instant help from the Needle AI that has access to the latest code, documentation and our integrations.

    Discord

    Chat with the community and share your projects in Needle Discord

    Get Inspired

    Watch some of our user interviews on youtube to get inspired.

    ',8)),o(n,{src:"https://www.youtube.com/watch?v=gZuC40Alr88"}),o(n,{src:"https://www.youtube.com/watch?v=F6_buCHZhWk"}),e[1]||(e[1]=t("div",{class:"hint-container info"},[t("p",{class:"hint-container-title"},"You made a cool project?"),t("p",null,[a("Don't hestitate to "),t("a",{href:"mailto:hi@needle.tools",target:"_blank",rel:"noopener noreferrer"},"reach out"),a(" โ€“ we always love seeing what you built ๐Ÿ’š")])],-1))])}const m=r(p,[["render",h],["__file","support.html.vue"]]),b=JSON.parse('{"path":"/support.html","title":"Support and Community","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/support.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[{"level":2,"title":"Forum","slug":"forum","link":"#forum","children":[]},{"level":2,"title":"Discord","slug":"discord","link":"#discord","children":[]},{"level":2,"title":"Get Inspired","slug":"get-inspired","link":"#get-inspired","children":[]}],"git":{"updatedTime":1727681911000},"filePathRelative":"support.md"}');export{m as comp,b as data}; diff --git a/assets/technical-overview.html-BeSwd6Mh.js b/assets/technical-overview.html-BeSwd6Mh.js new file mode 100644 index 000000000..b58ecdca9 --- /dev/null +++ b/assets/technical-overview.html-BeSwd6Mh.js @@ -0,0 +1,254 @@ +import{_ as t,r as h,o as e,c as l,e as a,a as k,d as i,b as p,w as r}from"./app-CRZRGfEE.js";const d={};function C(B,s){const n=h("RouteLink");return e(),l("div",null,[s[3]||(s[3]=a(`

    Technical Overview

    How it works

    Needle Engine roughly consists of three parts:

    • a number of components and tools that allow you to set up scenes for Needle Engine from e.g. the Unity Editor.
    • an exporter that turns scene and component data into glTF.
    • a web runtime that loads and runs the produced glTF files and their extensions.

    The web runtime uses three.js for rendering, adds a component system on top of the three scene graph and hooks up extension loaders for our custom glTF extensions.

    Effectively, this turns tools like Unity or Blender into spatial web development powerhouses โ€“ adding glTF assets to the typical HTML, CSS, JavaScript and bundling workflow.

    glTF Assets

    Models, textures, animations, lights, cameras and more are stored as glTF 2.0 files in Needle Engine.
    Custom data is stored in vendor extensions. These cover everything from interactive components to physics, sequencing and lightmaps.

    Supported glTF extensions

    A typical production glTF created by Needle Engine uses the following extensions:

    KHR_lights_punctual
    +KHR_materials_unlit
    +KHR_texture_transform
    +KHR_animation_pointer
    +NEEDLE_techniques_webgl
    +NEEDLE_gameobject_data
    +NEEDLE_components
    +NEEDLE_persistent_assets
    +NEEDLE_lightmaps
    +NEEDLE_lighting_settings
    +KHR_texture_basisu
    +KHR_draco_mesh_compression

    Other supported extensions:

    EXT_meshopt_compression
    +EXT_mesh_gpu_instancing (import and export)

    Supported material extensions:

    KHR_materials_clearcoat
    +KHR_materials_ior
    +KHR_materials_specular
    +KHR_materials_transmission
    +KHR_materials_iridescence
    +KHR_materials_unlit
    +KHR_materials_volume

    More extensions and custom extensions can be added using the export callbacks of UnityGLTF (not documented yet) and the glTF import extensions of three.js.

    Note: Materials using these extensions can be exported from Unity via UnityGLTF's PBRGraph material.

    Note: Audio and variants are already supported in Needle Engine through NEEDLE_components and NEEDLE_persistent_assets, but there are some options for more alignment to existing proposals such as KHR_audio and KHR_materials_variants.

    Learn more about GLTF loading in three.js

    Compression

    For production, we compress glTF assets with glTF-transform. Textures use either etc1s, uastc, webp or no compression, depending on texture type. Meshes use draco by default but can be configured to use meshtopt (per glTF file). Custom extensions are passed through in an opaque way.

    `,21)),k("p",null,[s[1]||(s[1]=i("See the ")),p(n,{to:"/deployment.html#optimization-and-compression-options"},{default:r(()=>s[0]||(s[0]=[i("deployment & compression")])),_:1}),s[2]||(s[2]=i(" page for more information"))]),s[4]||(s[4]=a(`

    Vendor-specific glTF Extensions (NEEDLE_*)

    Needle Engine stores custom data in glTF files through our vendor extensions. These extensions are designed to be flexible and allow relatively arbitrary data to put into them. Notably, no code is stored in these files. Interactive components is restored from the data at runtime. This has some similarities to how AssetBundles function in Unity โ€“ the receiving side of an asset needs to have matching code for components stored in the file.

    We're currently not prodiving schemas for these extensions as they are still in development. The JSON snippets below demonstrates extension usage by example and includes notes on architectural choices and what we may change in future releases.

    References between pieces of data are currently constructed through a mix of indices into other parts of the glTF file and JSON pointers. We may consolidate these approaches in a future release. We're also storing string-based GUIDs for cases where ordering is otherwise hard to resolve (e.g. two components referencing each other) that we may remove in the future.

    NEEDLE_components

    This extension contains per-node component data. The component names map to type names on both the JavaScript and C# side.
    Multiple components with the same name can be added to the same node.

    Data in NEEDLE_components can be animated via the currently not ratified KHR_animation_pointer extension.

    "NEEDLE_components": {
    +  "builtin_components": [
    +    {
    +      "name": "WebARSessionRoot",
    +      "guid": "1516450550",
    +      "arScale": 50,
    +      "invertForward": true,
    +      "enabled": true,
    +      "gameObject": {
    +        "node": 0
    +      }
    +    },
    +    {
    +      "name": "SyncedRoom",
    +      "guid": "1516450552",
    +      "roomName": "network-room",
    +      "urlParameterName": "room",
    +      "joinRandomRoom": true,
    +      "requireRoomParameter": false,
    +      "autoRejoin": true,
    +      "enabled": true,
    +      "gameObject": {
    +        "node": 0
    +      }
    +    },
    +    {
    +      "name": "PlayableDirector",
    +      "guid": "2243275882009986562_1668529989451832962",
    +      "state": 0,
    +      "extrapolationMode": 1,
    +      "playableAsset": "extensions/NEEDLE_persistent_assets/4",
    +      "playableGraph": {},
    +      "playOnAwake": true,
    +      "timeUpdateMode": 0,
    +      "time": 0,
    +      "initialTime": 0,
    +      "duration": 135.383333333332,
    +      "enabled": true,
    +      "gameObject": {
    +        "node": 0
    +      }
    +    }
    +  ]
    +}

    Note: Storing only the component type name means that type names currently need to be unique per project. We're planning to include package names in a future release to loosen this constraint to unique component type names per package instead of globally.

    Note: Currently there's no versioning information in the extension (which npm packaage does a component belong to, which version of that package was it exported against). We're planning to include versioning information in a future release.

    Note: Currently all components are in the builtin_components array. We might rename this to just components in a future release.

    NEEDLE_gameobject_data

    This extension contains additional per-node data related to state, layers, and tags. Layers are used for both rendering and physics, similar to how three.js and Unity treat them.

    "NEEDLE_gameobject_data": {
    +  "layers": 0,
    +  "tag": "Untagged",
    +  "hideFlags": 0,
    +  "static": false,
    +  "activeSelf": true,
    +  "guid": "1516450549"
    +}

    Note: We may need to better explain why this is not another entry in NEEDLE_components.

    NEEDLE_lighting_settings

    This is a root extension defining ambient lighting properties per glTF file.

    "NEEDLE_lighting_settings": {
    +  "ambientMode": 0,
    +  "ambientLight": [
    +    0.212,
    +    0.227,
    +    0.259,
    +    1
    +  ],
    +  "ambientIntensity": 1,
    +  "defaultReflectionMode": 0
    +}

    Note: This extension might have to be defined per-scene instead of per-file.

    NEEDLE_lightmaps

    This is a root extension defining a set of lightmaps for the glTF file.

    "NEEDLE_lightmaps": {
    +  "textures": [
    +    {
    +      "pointer": "textures/20",
    +      "type": 1,
    +      "index": 0
    +    }
    +  ]
    +}

    Note: At the moment this extension also contains environment texture references. We're planning to change that in a future release.

    Texture TypeValue
    Lightmap0
    Environment Map1
    Reflection Map2

    How lightmaps are applied is defined in the MeshRenderer component inside the NEEDLE_components extension per node:

    "NEEDLE_components": {
    +  "builtin_components": [
    +    {
    +      "name": "MeshRenderer",
    +      ...
    +      "lightmapIndex": 0,
    +      "lightmapScaleOffset": {
    +        "x": 1.00579774,
    +        "y": 1.00579774,
    +        "z": -0.00392889744,
    +        "w": -0.00392889744
    +      },
    +      ...
    +    }
    +  ]
    +}

    Note: We may change that in a future release and move lightmap-related data to a NEEDLE_lightmap extension entry per node.

    NEEDLE_persistent_assets

    Components in NEEDLE_components can reference data via JSON Pointers. The data in NEEDLE_persistent_assets is often referenced multiple times by different components and is thus stored separately in a root extension. By design, they are always referenced by something else (or have references within each other), and thus do not store type information at all: they're simply pieces of JSON data and components referencing them currently need to know what they expect.

    Examples for assets/data stored in here are:

    • AnimatorControllers, their layers and states
    • PlayableAssets (timelines), their tracks and embedded clips
    • SignalAssets
    • ...

    Data in persistent_assets can reference other persistent_assets via JSON Pointer, but by design can't reference NEEDLE_components. This is similar to the separation beween "Scene data" and "AssetDatabase content" in Unity.

    {
    +  "name": "LampionController",
    +  "guid": "9100000_ecab75bc7ab51a747a4c5c14236a43cd",
    +  "parameters": [],
    +  "layers": [
    +    {
    +      "name": "Base Layer",
    +      "stateMachine": {
    +        "name": "Base Layer",
    +        "defaultState": 0,
    +        "states": [
    +          {
    +            "name": "LampionFlying",
    +            "hash": 677739540,
    +            "motion": {
    +              "name": "LampionFlying",
    +              "isLooping": false,
    +              "guid": "7400000_c296c4d76e956b34f8b5833ba90653c1",
    +              "clips": [
    +                {
    +                  "node": "nodes/4",
    +                  "clip": "animations/0"
    +                },
    +                {
    +                  "node": "nodes/9",
    +                  "clip": "animations/6"
    +                },
    +                {
    +                  "node": "nodes/14",
    +                  "clip": "animations/12"
    +                }
    +              ]
    +            },
    +            "transitions": [
    +              {
    +                "isExit": false,
    +                "exitTime": 1,
    +                "hasFixedDuration": true,
    +                "offset": 0,
    +                "duration": 0,
    +                "hasExitTime": true,
    +                "destinationState": 0,
    +                "conditions": []
    +              }
    +            ]
    +          }
    +        ],
    +        "entryTransitions": []
    +      }
    +    }
    +  ]
    +},
    +{
    +  "name": "TrongCom Website",
    +  "guid": "11400000_93a8f856fe26af8498d94efe4835af36",
    +  "tracks": [
    +    {
    +      "name": "Markers",
    +      "type": "MarkerTrack",
    +      "muted": false,
    +      "outputs": [
    +        null
    +      ],
    +      "clips": [],
    +      "markers": [],
    +      "trackOffset": null
    +    },
    +    {
    +      "name": "Animation Track",
    +      "type": "AnimationTrack",
    +      "muted": false,
    +      "outputs": [
    +        "5017454109690854928_1668529989451832962"
    +      ],
    +      "clips": [
    +        {
    +          "start": 0,
    +          "end": 0.9833333333333333,
    +          "duration": 0.9833333333333333,
    +          "timeScale": 1,
    +          "asset": {
    +            "clip": "animations/78",
    +            "loop": false,
    +            "duration": 8,
    +            "position": {
    +              "x": 0,
    +              "y": 0,
    +              "z": 0
    +            },
    +            "rotation": {
    +              "x": 0,
    +              "y": 0,
    +              "z": 0,
    +              "w": 1
    +            },
    +            "removeStartOffset": true
    +          },
    +          "clipIn": 0,
    +          "easeInDuration": 0,
    +          "easeOutDuration": 0.41666666666666663,
    +          "preExtrapolationMode": 1,
    +          "postExtrapolationMode": 1
    +        },
    +        ... 
    +      ]
    +    }
    +  ]
    +}

    Note: We might include more type and versioning information in the future.

    NEEDLE_techniques_webgl

    This extension builds upon the archived KHR_techniques_webgl extension and extends it in a few crucial places. While the original extension was specified against WebGL 1.0, we're using it with WebGL 2.0 here and have added a number of uniform types.

    "KHR_techniques_webgl": {
    +  "programs": [
    +    {
    +      "vertexShader": 1,
    +      "fragmentShader": 0,
    +      "id": 0
    +    }
    +  ],
    +  "shaders": [
    +    {
    +      "name": "Pass-FRAGMENT",
    +      "type": 35632,
    +      "uri": "<embedded WebGL fragment shader code ...>",
    +      "id": 1
    +    },
    +    {
    +      "name": "Pass-VERTEX",
    +      "type": 35633,
    +      "uri": "<embedded WebGL vertex shader code ...>",
    +      "id": 0
    +    }
    +  ],
    +  "techniques": [
    +    {
    +      "program": 0,
    +      "attributes": {},
    +      "uniforms": {
    +        "_TimeParameters": {
    +          "name": "_TimeParameters",
    +          "type": 35666,
    +          "semantic": null,
    +          "count": 1,
    +          "node": 0
    +        },
    +        "hlslcc_mtx4x4unity_MatrixVP": {
    +          "name": "hlslcc_mtx4x4unity_MatrixVP",
    +          "type": 35666,
    +          "semantic": "_VIEWPROJECTION",
    +          "count": 4,
    +          "node": 0
    +        }
    +      },
    +      "defines": []
    +    }
    +  ]
    +}

    Note: Currently, vertex and fragment shaders are always embedded as URI; we plan on moving that data into more reasonable bufferViews in the future.

    Note: There's some redundant properties in here that we plan on cleaning up.

    TypeScript and Data Mapping

    ๐Ÿ—๏ธ Under Construction

    Rendering with three.js

    ๐Ÿ—๏ธ Under Construction

    Why aren't you compiling to WebAssembly?

    While Unity's compilation process from C# to IL to C++ (via IL2CPP) to WASM (via emscripten) is ingenious, it's also relatively slow. Building even a simple project to WASM takes many minutes, and that process is pretty much repeated on every code change. Some of it can be avoided through clever caching and ensuring that dev builds don't try to strip as much code, but it still stays slow.

    We do have a prototype for some WASM translation, but it's far from complete and the iteration speed stays slow, so we are not actively investigating this path right now.

    When looking into modern web workflows, we found that code reload times during development are neglectible, usually in sub-second ranges. This of course trades some performance (interpretation of JavaScript on the fly instead of compiler optimization at build time) for flexibility, but browsers got really good at getting the most out of JavaScript.

    We believe that for iteration and tight testing workflows, it's beneficial to be able to test on device and on the target platform (the browser, in this case) as quickly and as often as possible - which is why we're skipping Unity's entire play mode, effectively always running in the browser.

    Note: A really nice side effect is avoiding the entire slow "domain reload" step that usually costs 15-60 seconds each time you enter Play Mode. You're just "live" in the browser the moment you press Play.

    `,49))])}const g=t(d,[["render",C],["__file","technical-overview.html.vue"]]),y=JSON.parse(`{"path":"/technical-overview.html","title":"Technical Overview","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/technical overview.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[{"level":2,"title":"How it works","slug":"how-it-works","link":"#how-it-works","children":[]},{"level":2,"title":"glTF Assets","slug":"gltf-assets","link":"#gltf-assets","children":[{"level":3,"title":"Supported glTF extensions","slug":"supported-gltf-extensions","link":"#supported-gltf-extensions","children":[]},{"level":3,"title":"Compression","slug":"compression","link":"#compression","children":[]}]},{"level":2,"title":"Vendor-specific glTF Extensions (NEEDLE_*)","slug":"vendor-specific-gltf-extensions-needle","link":"#vendor-specific-gltf-extensions-needle","children":[{"level":3,"title":"NEEDLE_components","slug":"needle-components","link":"#needle-components","children":[]},{"level":3,"title":"NEEDLE_gameobject_data","slug":"needle-gameobject-data","link":"#needle-gameobject-data","children":[]},{"level":3,"title":"NEEDLE_lighting_settings","slug":"needle-lighting-settings","link":"#needle-lighting-settings","children":[]},{"level":3,"title":"NEEDLE_lightmaps","slug":"needle-lightmaps","link":"#needle-lightmaps","children":[]},{"level":3,"title":"NEEDLE_persistent_assets","slug":"needle-persistent-assets","link":"#needle-persistent-assets","children":[]},{"level":3,"title":"NEEDLE_techniques_webgl","slug":"needle-techniques-webgl","link":"#needle-techniques-webgl","children":[]}]},{"level":2,"title":"TypeScript and Data Mapping","slug":"typescript-and-data-mapping","link":"#typescript-and-data-mapping","children":[]},{"level":2,"title":"Rendering with three.js","slug":"rendering-with-three.js","link":"#rendering-with-three.js","children":[]},{"level":2,"title":"Why aren't you compiling to WebAssembly?","slug":"why-aren-t-you-compiling-to-webassembly","link":"#why-aren-t-you-compiling-to-webassembly","children":[]}],"git":{"updatedTime":1725399379000},"filePathRelative":"technical-overview.md"}`);export{g as comp,y as data}; diff --git a/assets/testimonial-yd4jmUbJ.js b/assets/testimonial-yd4jmUbJ.js new file mode 100644 index 000000000..de5c8924c --- /dev/null +++ b/assets/testimonial-yd4jmUbJ.js @@ -0,0 +1 @@ +import{_ as o,o as n,c as r,a as e,f as i,d as c,t as _}from"./app-CRZRGfEE.js";const d={props:{name:String,src:String}},l={class:"root"},f={class:"testimonial"},m={class:"quote"},p={class:"name"},u=["href"];function h(a,t,s,g,v,S){return n(),r("div",l,[e("div",f,[e("span",m,[i(a.$slots,"default",{},void 0,!0)]),e("span",p,[t[0]||(t[0]=c(" โ€” ")),e("a",{href:s.src,target:"_blank"},_(s.name),9,u)])])])}const x=o(d,[["render",h],["__scopeId","data-v-47fef520"],["__file","testimonial.vue"]]);export{x as default}; diff --git a/assets/testimonials.html-B3wqsnkd.js b/assets/testimonials.html-B3wqsnkd.js new file mode 100644 index 000000000..488f6c4cb --- /dev/null +++ b/assets/testimonials.html-B3wqsnkd.js @@ -0,0 +1 @@ +import{_ as o,r,o as l,c as m,a,b as s,w as i,d as n}from"./app-CRZRGfEE.js";const d={};function u(h,t){const e=r("testimonial");return l(),m("div",null,[t[12]||(t[12]=a("h1",{id:"testimonials",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#testimonials"},[a("span",null,"Testimonials")])],-1)),t[13]||(t[13]=a("p",null,null,-1)),s(e,{name:"Rinesh Thomas",src:"https://twitter.com/rineshthomas/status/1566342798063947777?t=z6sG3Z7mol-NfIRfTTKqCQ&s=19"},{default:i(()=>t[0]||(t[0]=[n(" This is the best thing I have seen after cinemachine in unity. Unity should acquire this ")])),_:1}),s(e,{name:"Chris Mahoney",src:"https://twitter.com/mahoneymatic/status/1562981022932684800?t=qNqojoZkk2CZrJa7dGzqng&s=19"},{default:i(()=>t[1]||(t[1]=[n(" Unbelievable Unity editor integration by an order of magnitude, and as straightforward as the docs claim. Wow. ")])),_:1}),s(e,{name:"Kevin Curry",src:"https://twitter.com/kmcurry/status/1574333302022062080"},{default:i(()=>t[2]||(t[2]=[n(" needle.tools is a wonderful showcase of what @NeedleTools contributes to 3D via the web. I just love it. ")])),_:1}),s(e,{name:"Stella Cannefax",src:"https://twitter.com/0xstella/status/1574853012585172993"},{default:i(()=>t[3]||(t[3]=[n(" Thanks to @NeedleTools, seeing quite a bit of this solution for web-based real time 3d tools - export scenes from Unity, where you can leverage the extensive 3d editor ecosystem & content, and then render them in your own web-based engine ")])),_:1}),s(e,{name:"Brit Gardner",src:"https://twitter.com/britg/status/1562443905580163072"},{default:i(()=>t[4]||(t[4]=[n(" Played with this a bit this morning ๐Ÿคฏ๐Ÿคฏ pretty magical ")])),_:1}),s(e,{name:"Marc Wakefield",src:"https://twitter.com/mrm_design/status/1567391880169545729"},{default:i(()=>t[5]||(t[5]=[n(" This is huge for WebXR and shared, immersive 3D experiences! Thank you so much for putting in the work on this @NeedleTools crew! Hoping @Apple sort out their WebXR situation sooner rather than later. The AR part worked flawlessly on my @SamsungMobile S21. ")])),_:1}),s(e,{name:"Pete Patterson",src:"https://twitter.com/VRSpatialist/status/1572300394285383680"},{default:i(()=>t[6]||(t[6]=[n(" Finally checking out @NeedleTools with Unity. Super easy to get something up and running in the cloud using their glitch integration ")])),_:1}),s(e,{name:"Dilmer Valecillos",src:"https://twitter.com/Dilmerv/status/1562209049856188420"},{default:i(()=>t[7]||(t[7]=[n(" This is amazing and if you are curious about #WebXR with Unity this will help us get there ")])),_:1}),s(e,{name:"VRSpatialist",src:"https://discord.com/channels/717429793926283276/722046635525537842/1030201907513405530"},{default:i(()=>t[8]||(t[8]=[n(" I am a long time Unity dev and recently started playing with Needle Tools and I love it! It's a great on ramp for Unity devs who want to learn WebXR and three.js. The runtime engine is awesome and it was pretty easy to create my own custom component ")])),_:1}),s(e,{name:"Unity for Digital Twins",src:"https://twitter.com/DigitalTwin/status/1576934958681055233"},{default:i(()=>t[9]||(t[9]=[n(" We just gotta say WOW ๐Ÿคฉ ")])),_:1}),s(e,{name:"Matthew Pieri",src:"https://discord.com/channels/717429793926283276/1097572505738301571/1097572505738301571"},{default:i(()=>t[10]||(t[10]=[n(" Spent the last 2.5 months building this game, never built a game/never used unity before, but absolutely loving the whole process with needle tools. So rapid! Would love to make a career building AR experiences! ")])),_:1}),s(e,{name:"Yuzu",src:"https://discord.com/channels/717429793926283276/1264966222467043433/1265268833485066240"},{default:i(()=>t[11]||(t[11]=[n(" My workflow has been optimized 10X ever since i started using needle ")])),_:1})])}const g=o(d,[["render",u],["__file","testimonials.html.vue"]]),f=JSON.parse('{"path":"/testimonials.html","title":"Testimonials","lang":"en-US","frontmatter":{"next":"getting-started/","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/testimonials.png"}],["meta",{"name":"og:description","content":"---\\nThis is the best thing I have seen after cinemachine in unity. Unity should acquire this"}]],"description":"---\\nThis is the best thing I have seen after cinemachine in unity. Unity should acquire this"},"headers":[],"git":{"updatedTime":1727125836000},"filePathRelative":"testimonials.md"}');export{g as comp,f as data}; diff --git a/assets/testing.html-DcypmV_S.js b/assets/testing.html-DcypmV_S.js new file mode 100644 index 000000000..b939ec727 --- /dev/null +++ b/assets/testing.html-DcypmV_S.js @@ -0,0 +1 @@ +import{_ as t,o as i,c as n,e as o}from"./app-CRZRGfEE.js";const a="/docs/testing/switch-to-mkcert.webp",r={};function s(l,e){return i(),n("div",null,e[0]||(e[0]=[o('

    Testing on local devices

    When using our templates, Needle Engine runs a local development server for you. Simply press play, and a website will open in your default browser, ready for testing on your local device. For testing on other devices in the same network, you may have to install a self-signed certificate (see below).

    When using a custom setup / framework, please refer to your framework's documentation on how to run a secure local development server.

    Tips

    Our local server uses the IP address in your local network (e.g. https://192.168.0.123:3000) instead of localhost:3000. This allows you to quickly view and test your project from mobile devices, VR glasses, and other machines in the same network.

    We're using HTTPS instead of the older HTTP, because modern powerful web APIs like WebXR require a secure connection โ€“ the S stands for "secure".

    Setting up a self-signed certificate for development

    Different operating systems have different security requirements for local development. Typically, displaying a website will work even with a auto-generated untrusted certificate, but browsers may warn about the missing trust and some features are not available. Here's a summary:

    Tips

    Installing trusted self-signed certificates on your development devices is recommended for a smooth development experience. Find the steps at the bottom of this page.

    Default โ€“ with auto-generated untrusted certificate
    Displays a certificate warning upon opening the project in a browser.Uses the vite-plugin-basic-ssl npm package.

    We're using websocket connections to communicate between the browser and the local development server. Websockets require a secure connection (HTTPS) in order to work. Depending on the platform, you might need to set up a custom certificate for local development. Android and Windows don't need a custom certificate, but iOS and MacOS do.

    OSViewing in the browser
    (with a security warning)
    Automatic reloads
    Windows(โœ“)โœ“
    Linux(โœ“)โœ“
    Android(โœ“)โœ“
    macOS(โœ“)โŒ
    iOS(โœ“ Safari and Chrome, after page reload)
    โŒ Mozilla XR Viewer
    โŒ
    Xcode Simulators(โœ“ after page reload)โŒ

    With a self-signed, trusted root certificate
    No security warning is displayed. You need to install the generated certificate on your device(s).
    Uses the vite-plugin-mkcert npm package.

    OSViewing in the browserAutomatic reloads
    Windowsโœ“โœ“
    Linuxโœ“โœ“
    Androidโœ“โœ“
    macOSโœ“โœ“
    iOSโœ“โœ“

    Generating a self-signed development certificate

    • in Unity/Blender, click on "Open Workspace" to open VS Code

    • check that you're using vite-plugin-mkcert instead of vite-plugin-basic-ssl (the latter doesn't generate a trusted root certificate, which we need) in your vite.config.ts file:

      • open package.json
      • remove the line with "@vitejs/plugin-basic-ssl" from devDependencies
      • open a Terminal in VS Code and run npm install vite-plugin-mkcert --save-dev which will add the latest version
      • open vite.config.ts and replace import basicSsl from '@vitejs/plugin-basic-ssl' with import mkcert from'vite-plugin-mkcert'
      • in plugins: [, replace basicSsl(), with mkcert(),
      • package.json looks like this now:
    • run npm run start once from VS Code's terminal

      • on Windows, this will open a new window and guide you through the creation and installation of the certificate
      • on MacOS, the terminal prompts for your password and then generates and installs the certificate.
      • if you're getting an error Error: Port 3000 is already in use, please close the server that may still be running from Unity.
    • the generated certificate will automatically be installed on the machine you generated it on.

    • you can stop the terminal process again.

    • from now on, pressing Play in Unity/Blender will use the generated certificate for the local server, and no "security warning" will be shown anymore, since your browser now trusts the local connection.

    Installing the certificate on your development devices

    On your development devices, you need to install the generated certificate and allow the OS to trust it. This is different for each OS. For each of them, you'll need the rootCA.pem file that was generated, and send it to the device you want to authenticate.

    On Windows: find the certificate in Users/<your-user>/.vite-plugin-mkcert/rootCA.pem
    On MacOS: find the certificate in Users/<your-user>/.vite-plugin-mkcert/rootCA.pem

    Send the device to yourself (e.g. via E-Mail, AirDrop, iCloud, USB, Slack, ...) so that you can access it on your development devices.

    Installing the certificate on Android

    1. Open the file. You'll be prompted to install the certificate.

    Installing the certificate on iOS / iPadOS / VisionOS

    1. Open the file.
    2. You'll be prompted to add the profile to your device. Confirm.
    3. Go to Settings
    4. There will be a new entry "Profile". Select it and allow the profile to be active for this device.
    5. On iOS / iPadOS, you also need to allow "Root Certificate Trust". For this, search for Trust or go to Settings > General > About > Info > Certificate Trust Settings and enable full trust for the root certificate.

    Tips

    The certificate is automatically installed on the machine you generated it on. For other machines in the local network, follow the steps below to also establish a trusted connection.

    Installing the certificate on another MacOS machine

    1. Open the file. Keychain Access will open and allow you to install the certificate.
    2. You may have to set "Trust" to "Always allow".

    Installing the certificate on another Windows machine

    1. Open certmgr ("Manage user certificates") by typing Windows key + certmgr.
    2. In the left sidebar, select "Trusted Root Certification Authorities".
    3. Right-click on "Certificates" and select "All Tasks > Import".
    4. Select the rootCA.pem file (you may have to change the file type to "all") and follow the instructions.
    ',27)]))}const d=t(r,[["render",s],["__file","testing.html.vue"]]),h=JSON.parse(`{"path":"/testing.html","title":"Testing on local devices","lang":"en-US","frontmatter":{"title":"Testing on local devices","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/testing on local devices.png"}],["meta",{"name":"og:description","content":"---\\nWhen using our templates, Needle Engine runs a local development server for you. Simply press play, and a website will open in your default browser, ready for testing on your local device. For testing on other devices in the same network, you may have to install a self-signed certificate (see below).\\nWhen using a custom setup / framework, please refer to your framework's documentation on how to run a secure local development server.\\n::: tip\\nOur local server uses the IP address in your local network (e.g. https://192.168.0.123:3000) instead of localhost:3000. This allows you to quickly view and test your project from mobile devices, VR glasses, and other machines in the same network.\\nWe're using HTTPS instead of the older HTTP, because modern powerful web APIs like WebXR require a secure connection โ€“ the S stands for 'secure'.\\n:::\\nDifferent operating systems have different security requirements for local development. Typically, displaying a website will work even with a auto-generated untrusted certificate, but browsers may warn about the missing trust and some features are not available. Here's a summary:\\n::: tip\\nInstalling trusted self-signed certificates on your development devices is recommended for a smooth development experience. Find the steps at the bottom of this page.\\n:::\\nDefault โ€“ with auto-generated untrusted certificate\\n_Displays a certificate warning upon opening the project in a browser._\\n_Uses the vite-plugin-basic-ssl npm package._\\nWe're using websocket connections to communicate between the browser and the local development server. Websockets require a secure connection (HTTPS) in order to work. Depending on the platform, you might need to set up a custom certificate for local development. Android and Windows don't need a custom certificate, but iOS an"}]],"description":"---\\nWhen using our templates, Needle Engine runs a local development server for you. Simply press play, and a website will open in your default browser, ready for testing on your local device. For testing on other devices in the same network, you may have to install a self-signed certificate (see below).\\nWhen using a custom setup / framework, please refer to your framework's documentation on how to run a secure local development server.\\n::: tip\\nOur local server uses the IP address in your local network (e.g. https://192.168.0.123:3000) instead of localhost:3000. This allows you to quickly view and test your project from mobile devices, VR glasses, and other machines in the same network.\\nWe're using HTTPS instead of the older HTTP, because modern powerful web APIs like WebXR require a secure connection โ€“ the S stands for 'secure'.\\n:::\\nDifferent operating systems have different security requirements for local development. Typically, displaying a website will work even with a auto-generated untrusted certificate, but browsers may warn about the missing trust and some features are not available. Here's a summary:\\n::: tip\\nInstalling trusted self-signed certificates on your development devices is recommended for a smooth development experience. Find the steps at the bottom of this page.\\n:::\\nDefault โ€“ with auto-generated untrusted certificate\\n_Displays a certificate warning upon opening the project in a browser._\\n_Uses the vite-plugin-basic-ssl npm package._\\nWe're using websocket connections to communicate between the browser and the local development server. Websockets require a secure connection (HTTPS) in order to work. Depending on the platform, you might need to set up a custom certificate for local development. Android and Windows don't need a custom certificate, but iOS an"},"headers":[{"level":2,"title":"Testing on local devices","slug":"testing-on-local-devices","link":"#testing-on-local-devices","children":[]},{"level":2,"title":"Setting up a self-signed certificate for development","slug":"setting-up-a-self-signed-certificate-for-development","link":"#setting-up-a-self-signed-certificate-for-development","children":[{"level":3,"title":"Generating a self-signed development certificate","slug":"generating-a-self-signed-development-certificate","link":"#generating-a-self-signed-development-certificate","children":[]}]},{"level":2,"title":"Installing the certificate on your development devices","slug":"installing-the-certificate-on-your-development-devices","link":"#installing-the-certificate-on-your-development-devices","children":[{"level":3,"title":"Installing the certificate on Android","slug":"installing-the-certificate-on-android","link":"#installing-the-certificate-on-android","children":[]},{"level":3,"title":"Installing the certificate on iOS / iPadOS / VisionOS","slug":"installing-the-certificate-on-ios-ipados-visionos","link":"#installing-the-certificate-on-ios-ipados-visionos","children":[]},{"level":3,"title":"Installing the certificate on another MacOS machine","slug":"installing-the-certificate-on-another-macos-machine","link":"#installing-the-certificate-on-another-macos-machine","children":[]},{"level":3,"title":"Installing the certificate on another Windows machine","slug":"installing-the-certificate-on-another-windows-machine","link":"#installing-the-certificate-on-another-windows-machine","children":[]}]}],"git":{"updatedTime":1689176384000},"filePathRelative":"testing.md"}`);export{d as comp,h as data}; diff --git a/assets/texture-compression-BuEaeBZn.js b/assets/texture-compression-BuEaeBZn.js new file mode 100644 index 000000000..e374e6f24 --- /dev/null +++ b/assets/texture-compression-BuEaeBZn.js @@ -0,0 +1 @@ +const e="/docs/blender/texture-compression.webp";export{e as _}; diff --git a/assets/tool-tile-DaqpZjM0.js b/assets/tool-tile-DaqpZjM0.js new file mode 100644 index 000000000..ca4bda8a2 --- /dev/null +++ b/assets/tool-tile-DaqpZjM0.js @@ -0,0 +1 @@ +import{_ as n,o as l,c as a,a as o,n as r,f as s,g as d}from"./app-CRZRGfEE.js";const c={props:{image:String,docs_url:String},methods:{getClass:u}};function u(){return this.$slots["video-tutorial"]?"":"small"}const _=["src"],m={class:"description"},f=["href"];function g(e,h,t,v,p,i){return l(),a("div",{class:r(["tile",i.getClass()])},[o("img",{src:t.image,alt:"Tool Image",class:r(t.image?"":"hidden")},null,10,_),o("h3",null,[s(e.$slots,"tool-name",{},void 0,!0)]),o("p",m,[s(e.$slots,"tool-description",{},void 0,!0)]),s(e.$slots,"download-button",{},void 0,!0),o("p",null,[s(e.$slots,"video-tutorial",{},void 0,!0)]),t.docs_url?(l(),a("a",{key:0,href:t.docs_url},"Next Steps",8,f)):d("",!0)],2)}const S=n(c,[["render",g],["__scopeId","data-v-c9f16638"],["__file","tool-tile.vue"]]);export{S as default}; diff --git a/assets/tool-tiles-BfEF3OW4.js b/assets/tool-tiles-BfEF3OW4.js new file mode 100644 index 000000000..65f6a97c3 --- /dev/null +++ b/assets/tool-tiles-BfEF3OW4.js @@ -0,0 +1 @@ +import{_ as a,r as s,o as u,c as g,a as n,b as l,w as e,d as o,F as m}from"./app-CRZRGfEE.js";const _={};function p(w,t){const d=s("needle-button"),i=s("video-embed"),r=s("tool-tile");return u(),g(m,null,[n("div",null,[l(r,{image:"/docs/imgs/unity-logo.webp",docs_url:"/docs/unity/"},{"tool-name":e(()=>t[0]||(t[0]=[o(" Needle ร— Unity ")])),"tool-description":e(()=>t[1]||(t[1]=[o(" Unity 2021.3 LTS"),n("br",null,null,-1),o(" Unity 2022.3 LTS"),n("br",null,null,-1),o(" Unity 6 ")])),"download-button":e(()=>[l(d,{event_goal:"download_unity",event_position:"getting_started",large:"",href:"https://engine.needle.tools/downloads/unity?utm_source=needle_docs&utm_content=getting_started",next_url:"./../unity/"},{default:e(()=>t[2]||(t[2]=[n("strong",null,"Download",-1)])),_:1})]),"video-tutorial":e(()=>[l(i,{src:"https://www.youtube.com/watch?v=gfslrxhkH3E",limit_height:"",max_height:"70xp"})]),_:1}),l(r,{image:"/docs/blender/logo.png",docs_url:"/docs/blender/"},{"tool-name":e(()=>t[3]||(t[3]=[o(" Needle ร— Blender ")])),"tool-description":e(()=>t[4]||(t[4]=[o(" Blender 4.0"),n("br",null,null,-1),o(" Blender 4.1"),n("br",null,null,-1),o(" Blender 4.2+ ")])),"download-button":e(()=>[l(d,{event_goal:"download_blender",event_position:"getting_started",large:"",href:"https://engine.needle.tools/downloads/blender?utm_source=needle_docs&utm_content=getting_started",next_url:"./../blender/"},{default:e(()=>t[5]||(t[5]=[n("strong",null,"Download",-1)])),_:1})]),"video-tutorial":e(()=>[l(i,{src:"https://www.youtube.com/watch?v=TXEHR4Cq7iU",limit_height:"",max_height:"70xp"})]),_:1})]),n("div",null,[l(r,{image:"/docs/imgs/logo-webcomponents.png"},{"tool-name":e(()=>t[6]||(t[6]=[o(" "),n("br",null,null,-1),o("Web Component ")])),"tool-description":e(()=>t[7]||(t[7]=[o(" Rich, interactive 3D content made easy ")])),"download-button":e(()=>[l(d,{event_goal:"download_webcomponent",event_position:"getting_started",large:"",same_tab:"",href:"/docs/three/"},{default:e(()=>t[8]||(t[8]=[n("strong",null,"Get Started",-1)])),_:1})]),_:1}),l(r,{image:"/docs/imgs/threejs-logo.webp"},{"tool-name":e(()=>t[9]||(t[9]=[o(" Needle ร— three.js ")])),"tool-description":e(()=>t[10]||(t[10]=[o(" three.js r162+ ")])),"download-button":e(()=>[l(d,{event_goal:"download_threejs",event_position:"getting_started",large:"",same_tab:"",href:"/docs/three/"},{default:e(()=>t[11]||(t[11]=[n("strong",null,"Get Started",-1)])),_:1})]),_:1}),l(r,null,{"tool-name":e(()=>t[12]||(t[12]=[o(" Other Workflows ")])),"tool-description":e(()=>t[13]||(t[13]=[o(" Learn how to integrate Needle Engine into your tool or workflow ")])),"download-button":e(()=>[l(d,{event_goal:"download_custom",event_position:"getting_started",large:"",same_tab:"",href:"/docs/custom-integrations/"},{default:e(()=>t[14]||(t[14]=[n("strong",null,"Learn More",-1)])),_:1})]),_:1})])],64)}const v=a(_,[["render",p],["__scopeId","data-v-90f1465a"],["__file","tool-tiles.vue"]]);export{v as default}; diff --git a/assets/typescript-decorators.html-DQAWNuRE.js b/assets/typescript-decorators.html-DQAWNuRE.js new file mode 100644 index 000000000..2f08e4ad4 --- /dev/null +++ b/assets/typescript-decorators.html-DQAWNuRE.js @@ -0,0 +1,56 @@ +import{_ as s,o as a,c as t,e as l}from"./app-CRZRGfEE.js";const n={};function e(h,i){return a(),t("div",null,i[0]||(i[0]=[l(`

    The following table contains available Typescript decorators that Needle Engine provides.

    You can think of them as Attributes on steroids (if you are familiar with C#) - they can be added to classes, fields or methods in Typescript to provide additional functionality.

    Field & Property Decorators
    @serializable()Add to exposed / serialized fields. Is used when loading glTF files that have been exported with components from Unity or Blender.
    @syncField()Add to a field to network the value when it changes. You can pass in a method to be called when the field changes
    @validate()Add to receive callbacks in the component event method onValidate whenever the value changes. This behaves similar to Unity's onValidate.
    Method Decorators
    @prefix(<type>) (experimental)Can be used to easily inject custom code into other components. Optionally return false to prevent the original method from being executed. See the example below
    Class Decorators
    @registerTypeNo argument. Can be added to a custom component class to be registered to the Needle Engine types and to enable hot reloading support.

    Examples

    Serializable

    import { Behaviour, serializable, EventList } from "@needle-tools/engine";
    +import { Object3D } from "three";
    +
    +export class SomeComponentType extends Behaviour {}
    +
    +export class ButtonObject extends Behaviour {
    +    // you can omit the type if it's a primitive 
    +    // e.g. Number, String or Bool
    +    @serializable()
    +    myNumber: number = 42;
    +
    +    // otherwise add the concrete type that you want to serialize to
    +    @serializable(EventList)
    +    onClick?: EventList;
    +
    +    @serializable(SomeComponentType)
    +    myComponent?: SomeComponentType;
    +
    +    // Note that for arrays you still add the concrete type (not the array)
    +    @serializable(Object3D)
    +    myObjects?: Object3D[];
    +}

    SyncField

    The @syncField decorator can be used to automatically network properties of your components for all users (visitors of your website) connected to the same networking room. It can optionally take a callback function that will be invoked whenever the value changes.

    • To notify the system that a reference value (like an object or an array) has changed you need to re-assign the field. E.g. like this: myField = myField
    • The callback function can not be an arrow function (e.g. MyScript.prototype.onNumberChanged works for onNumberChanged() { ... } but it does not for myNumberChanged = () => { ... })
    import { Behaviour, serializable, syncField } from "@needle-tools/engine";
    +
    +export class MyScript extends Behaviour {
    +
    +    @syncField(MyScript.prototype.onNumberChanged)
    +    @serializable()
    +    myNumber: number = 42;
    +
    +    private onNumberChanged(newValue: number, oldValue: number){
    +        console.log("Number changed from ", oldValue, "to", newValue)
    +    }
    +}

    Validate

    import { Behaviour, serializable, validate } from "@needle-tools/engine";
    +
    +export class MyScript extends Behaviour {
    +
    +    @validate()
    +    @serializable()
    +    myNumber?: number;
    +
    +    start() { setInterval(() => this.myNumber = Math.random(), 1000) }
    +
    +    onValidate(fieldName: string) {
    +        console.log("Validate", fieldName, this.myNumber);
    +    }
    +}

    Prefix

    Live example

    import { Camera, prefix } from "@needle-tools/engine";
    +class YourClass {
    +    @prefix(Camera) // < this is type that has the method you want to change
    +    awake() { // < this is the method name you want to change
    +
    +        // this is now called before the Camera.awake method runs
    +        // NOTE: \`this\` does now refer to the Camera instance and NOT \`YourClass\` anymore. This allows you to access internal state of the component as well
    +        console.log("Hello camera:", this)
    +        // optionally return false if you want to prevent the default behaviour
    +    }
    +}
    `,15)]))}const p=s(n,[["render",e],["__file","typescript-decorators.html.vue"]]),r=JSON.parse('{"path":"/reference/typescript-decorators.html","title":"@serializable and other decorators","lang":"en-US","frontmatter":{"title":"@serializable and other decorators","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/@serializable and other decorators.png"}],["meta",{"name":"og:description","content":"---\\nThe following table contains available Typescript decorators that Needle Engine provides.\\nYou can think of them as Attributes on steroids (if you are familiar with C#)"}]],"description":"---\\nThe following table contains available Typescript decorators that Needle Engine provides.\\nYou can think of them as Attributes on steroids (if you are familiar with C#)"},"headers":[{"level":2,"title":"Examples","slug":"examples","link":"#examples","children":[{"level":3,"title":"Serializable","slug":"serializable","link":"#serializable","children":[]},{"level":3,"title":"SyncField","slug":"syncfield","link":"#syncfield","children":[]},{"level":3,"title":"Validate","slug":"validate","link":"#validate","children":[]},{"level":3,"title":"Prefix","slug":"prefix","link":"#prefix","children":[]}]}],"git":{"updatedTime":1726585195000},"filePathRelative":"reference/typescript-decorators.md"}');export{p as comp,r as data}; diff --git a/assets/typescript-essentials.html-B7bTUCZ9.js b/assets/typescript-essentials.html-B7bTUCZ9.js new file mode 100644 index 000000000..1c6ea6675 --- /dev/null +++ b/assets/typescript-essentials.html-B7bTUCZ9.js @@ -0,0 +1,99 @@ +import{_ as t,r as n,o as h,c as e,e as l,a as s,b as k,w as p,d as r}from"./app-CRZRGfEE.js";const d={};function o(y,i){const a=n("RouteLink");return h(),e("div",null,[i[1]||(i[1]=l(`

    The following guide tries to highlight some of the key differences between C#, Javascript and Typescript. This is most useful for developers new to the web ecosystem.

    Here are also some useful resources for learning how to write Typescript:

    Key differences between C#, Javascript or Typescript

    CSharp or C# is a statically typed & compiled language. It means that before your code can run (or be executed) it has to be compiled - translated - into IL or CIL, an intermediate language that is a little closer to machine code. The important bit to understand here is that your code is analyzed and has to pass certain checks and rules that are enforced by the compiler. You will get compiler errors in Unity and your application not even start running if you write code that violates any of the rules of the C# language. You will not be able to enter Play-Mode with compiler errors.

    Javascript on the other hand is interpreted at runtime. That means you can write code that is not valid and cause errors - but you will not see those errors until your program runs or tries to execute exactly that line that has the error. For example you can write var points = 100; points += "hello world"; and nobody will complain until you run the code in a browser.

    Typescript is a language designed by Microsoft that compiles to javascript
    It adds a lot of features like for example type-safety. That means when you write code in Typescript you can declare types and hence get errors at compile-time when you try to e.g. make invalid assignments or call methods with unexpected types. Read more about types in Javascript and Typescript below.

    Types โ€” or the lack thereof

    Vanilla Javascript does (as of today) not have any concept of types: there is no guarantuee that a variable that you declared as let points = 100 will still be a number later in your application. That means that in Javascript it is perfectly valid code to assign points = new Vector3(100, 0, 0); later in your code. Or even points = null or points = myRandomObject - you get the idea. This is all OK while you write the code but it may crash horrible when your code is executed because later you write points -= 1 and now you get errors in the browser when your application is already running.

    As mentioned above Typescript was created to help fix that problem by adding syntax for defining types.

    It is important to understand that you basically still write Javascript when you write Typescript and while it is possible to circumvent all type checking and safety checks by e.g. adding //@ts-ignore above a erroneous line or defining all types as any this is definitely not recommneded. Types are here to help you find errors before they actually happen. You really dont want to deploy your website to your server only to later get reports from users or visitors telling you your app crashed while it was running.

    While vanilla Javascript does not offer types you can still add type-annotations to your javascript variables, classes and methods by using JSDoc.

    Variables

    In C# you write variables either by using the type or the var keyword.
    For example you can either write int points = 100;
    or alternatively use var and let the compiler figure out the correct type for you: var points = 100

    In Javascript or Typescript you have two modern options to declaring a variable.
    For a variable that you plan to re-assign use let, for example let points = 100;
    For a variable that you do not want to be able to re-assign use const, for example const points = 100;

    Be aware of var
    You might come across the var keyword in javascript as well but it is not recommended to use it and the modern replacement for it is let. Learn more about var vs let.

    Please note that you can still assign values to variables declared with const if they are (for example) a custom type. Consider the following example:

    import { Vector3 } from "three";
    +// ---cut-before---
    +const myPosition : Vector3 = new Vector3(0, 0, 0);
    +myPosition.x = 100; // Assigning x is perfectly fine

    The above is perfectly fine Typescript code because you don't re-assign myPosition but only the x member of myPosition. On the other hand the following example would not be allowed and cause a runtime or typescript error:

    // @errors: 2588
    +import { Vector3 } from "three";
    +// ---cut-before---
    +const myPosition : Vector3 = new Vector3(0, 0, 0);
    +myPosition = new Vector3(100, 0, 0); // โš  ASSIGNING TO CONST IS NOT ALLOWED

    Using or Importing Types

    In Unity you usually add using statements at the top of you code to import specific namespaces from Assemblies that are references in your project or - in certain cases - you migth find yourself importing a specific type with a name from a namespace.
    See the following example:

    using UnityEngine;
    +// importing just a specific type and giving it a name
    +using MonoBehaviour = UnityEngine.MonoBehaviour;

    This is how you do the same in Typescript to import specific types from a package:

    import { Vector3 } from 'three';
    +import { Behaviour } from '@needle-tools/engine';

    You can also import all the types from a specific package by giving it a name which you might see here and there:

    import * as THREE from 'three';
    +const myVector : THREE.Vector3 = new THREE.Vector3(1, 2, 3);

    Primitive Types

    Vector2, Vector3, Vector4...
    If you have a C# background you might be familiar with the difference between a class and a struct. While a class is a reference type a struct is a custom value type. Meaning it is, depending on the context, allocated on the stack and when being passed to a method by default a copy is created.
    Consider the following example in C#:

    void MyCallerMethod(){
    +    var position = new Vector3(0,0,0);
    +    MyExampleVectorMethod(position);
    +    UnityEngine.Debug.Log("Position.x is " + position.x); // Here x will be 0
    +}
    +void MyExampleVectorMethod(Vector3 position){
    +    position.x = 42;
    +}

    A method is called with a Vector3 named position. Inside the method the passed in vector position is modified: x is set to 42. But in C# the original vector that is being passed into this method (see line 2) is not changed and x will still be 0 (line 4).

    The same is not true for Javascript/Typescript. Here we don't have custom value types, meaning if you come across a Vector in Needle Engine or three.js you will always have a reference type.
    Consider the following example in typescript:

    import { Vector3 } from 'three'
    +
    +function myCallerMethod() : void {
    +    const position = new Vector3(0,0,0);
    +    myExampleVectorMethod(position);
    +    console.log("Position.x is " + position.x); // Here x will be 42
    +}
    +function myExampleVectorMethod(position: Vector3) : void {
    +    position.x = 42;
    +}

    Do you see the difference? Because vectors and all custom objects are in fact reference types we will have modified the original position variable (line 3) and x is now 42.

    This is not only important to understand for methods but also when working with variables.
    In C# the following code will produce two instances of Vector3 and changing one will not affect the other:

    var myVector = new Vector3(1,1,1);
    +var myOtherVector = myVector;
    +myOtherVector.x = 42;
    +// will log: 1, 42
    +UnityEngine.Debug.Log(myVector.x + ", " + myOtherVector.x);

    If you do the same in Typescript you will not create a copy but get a reference to the same myVector instance instead:

    import { Vector3 } from 'three'
    +
    +const myVector = new Vector3(1,1,1);
    +const myOtherVector = myVector;
    +myOtherVector.x = 42;
    +// will log: 42, 42
    +console.log(myVector.x, myOtherVector.x);

    Vector Maths and Operators

    While in C# you can use operator overloading this is not available in Javascript unfortunately. This means that while you can multiply a Vector3 in C# like this:

    var myFirstVector = new Vector3(1,1,1);
    +var myFactor = 100f;
    +myFirstVector *= myFactor;
    +// โ†’ myFirstVector is now 100, 100, 100

    you have to use a method on the Vector3 type to archieve the same result (just with a little more boilerplate code)

    import { Vector3 } from "three"
    +
    +const myFirstVector : Vector3 = new Vector3(1, 1, 1)
    +const myFactor = 100;
    +myFirstVector.multiplyScalar(myFactor);
    +// โ†’ myFirstVector is now 100, 100, 100

    Equality Checks

    loose vs strict comparison

    In C# when you want to check if two variables are the same you can write it as follows:

    var playerIsNull = myPlayer == null;

    in Javascript/Typescript there is a difference between == and === where === is more strictly checking for the type:

    const myPlayer: any = null;
    +// ---cut-before---
    +const playerIsNull = myPlayer === null;
    +const playerIsNullOrUndefined = myPlayer == null;

    You notice that the second variable playerIsNullOrUndefined is using == which does a loose equality check in which case null and undefined will both result in truehere. You can read more about that here

    Events, Binding and this

    When you subscribe to an Event in C# you do it like this:

    // this is how an event is declared
    +event Action MyEvent;
    +// you subscribe by adding to (or removing from)
    +void OnEnable() {
    +    MyEvent += OnMyEvent;
    +}
    +void OnDisable() {
    +    MyEvent -= OnMyEvent;
    +}
    +void OnMyEvent() {}

    In Typescript and Javascript when you add a method to a list you have to "bind this". That essentially means you create a method where you explictly set this to (usually) your current class instance. There are two way to archieve this.

    Please note that we are using the type EventList here which is a Needle Engine type to declare events (the EventList will also automatically be converted to a UnityEvent and or a event list in Blender when you use them with our Editor integrations)

    The short and recommended syntax for doing this is to use Arrow Functions.

    import { EventList, Behaviour, serializable } from "@needle-tools/engine";
    +
    +export class MyComponent extends Behaviour {
    +
    +    @serializable(EventList)
    +    myEvent!: EventList;
    +
    +    onEnable() {
    +        this.myEvent.addEventListener(this.onMyEvent);
    +    }
    +
    +    onDisable() {
    +        this.myEvent.removeEventListener(this.onMyEvent);
    +    }
    +
    +    // Declaring the function as an arrow function to automatically bind \`this\`
    +    private onMyEvent = () => {
    +        console.log(this !== undefined, this)
    +    }
    +}

    There is also the more verbose "classical" way to archieve the same thing by manually binding this (and saving the method in a variable to later remove it again from the event list):

    import { EventList, Behaviour, serializable } from "@needle-tools/engine";
    +
    +export class MyComponent extends Behaviour {
    +
    +    @serializable(EventList)
    +    myEvent?: EventList;
    +    
    +    private _onMyEventFn?: Function;
    +
    +    onEnable() {
    +        // bind this
    +        this._onMyEventFn = this.onMyEvent.bind(this);
    +        // add the bound method to the event
    +        this.myEvent?.addEventListener(this._onMyEventFn);
    +    } 
    +    
    +    onDisable() {
    +        this.myEvent?.removeEventListener(this._onMyEventFn);
    +    }
    +    
    +    // Declaring the function as an arrow function to automatically bind \`this\`
    +    private onMyEvent = () => { }
    +}

    What's next?

    `,60)),s("ul",null,[s("li",null,[k(a,{to:"/scripting.html"},{default:p(()=>i[0]||(i[0]=[r("Needle Engine Scripting")])),_:1})])])])}const c=t(d,[["render",o],["__file","typescript-essentials.html.vue"]]),C=JSON.parse(`{"path":"/getting-started/typescript-essentials.html","title":"Scripting in Needle Engine","lang":"en-US","frontmatter":{"title":"Scripting in Needle Engine","description":"Differences, similarities and key concepts of Typescript, Javascript and C#.","sidebarDepth":2,"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/scripting in needle engine.png"}],["meta",{"name":"og:description","content":"Differences, similarities and key concepts of Typescript, Javascript and C#."}]]},"headers":[{"level":3,"title":"Key differences between C#, Javascript or Typescript","slug":"key-differences-between-c-javascript-or-typescript","link":"#key-differences-between-c-javascript-or-typescript","children":[]},{"level":3,"title":"Types โ€” or the lack thereof","slug":"types-or-the-lack-thereof","link":"#types-or-the-lack-thereof","children":[]},{"level":3,"title":"Variables","slug":"variables","link":"#variables","children":[]},{"level":3,"title":"Using or Importing Types","slug":"using-or-importing-types","link":"#using-or-importing-types","children":[]},{"level":3,"title":"Primitive Types","slug":"primitive-types","link":"#primitive-types","children":[]},{"level":3,"title":"Vector Maths and Operators","slug":"vector-maths-and-operators","link":"#vector-maths-and-operators","children":[]},{"level":3,"title":"Equality Checks","slug":"equality-checks","link":"#equality-checks","children":[]},{"level":3,"title":"Events, Binding and this","slug":"events-binding-and-this","link":"#events-binding-and-this","children":[]},{"level":2,"title":"What's next?","slug":"what-s-next","link":"#what-s-next","children":[]}],"git":{"updatedTime":1726585195000},"filePathRelative":"getting-started/typescript-essentials.md"}`);export{c as comp,C as data}; diff --git a/assets/usdz-hide-object-on-start.html-Bd-eN8WF.js b/assets/usdz-hide-object-on-start.html-Bd-eN8WF.js new file mode 100644 index 000000000..92334301c --- /dev/null +++ b/assets/usdz-hide-object-on-start.html-Bd-eN8WF.js @@ -0,0 +1,22 @@ +import{_ as t,r as n,o as h,c as e,a as s,b as l,e as k}from"./app-CRZRGfEE.js";const p={};function r(d,i){const a=n("contribution-header");return h(),e("div",null,[i[0]||(i[0]=s("p",null,[s("a",{href:"/docs/community/contributions"},"Overview")],-1)),l(a,{url:"https://github.com/marwie",author:"marwie",page:"/docs/community/contributions/marwie",profileImage:"https://avatars.githubusercontent.com/u/5083203?s=100&v=4",githubUrl:"https://github.com/needle-tools/needle-engine-support/discussions/156",title:"USDZ: Hide Object on Start",gradient:"True"}),i[1]||(i[1]=k(`

    This is an example from our Everywhere Actions. The following script hides an object on start on Android and on iOS AR

    export class HideOnStart extends Behaviour implements UsdzBehaviour {
    +
    +    start() {
    +        this.gameObject.visible = false;
    +    }
    +
    +    createBehaviours(ext, model, _context) {
    +        if (model.uuid === this.gameObject.uuid)
    +            ext.addBehavior(new BehaviorModel("HideOnStart_" + this.gameObject.name,
    +                TriggerBuilder.sceneStartTrigger(),
    +                ActionBuilder.fadeAction(model, 0, false)
    +            ));
    +    }
    +
    +    beforeCreateDocument() {
    +        this.gameObject.visible = true;
    +    }
    +
    +    afterCreateDocument() {
    +        this.gameObject.visible = false;
    +    }
    +}
    `,2))])}const g=t(p,[["render",r],["__file","usdz-hide-object-on-start.html.vue"]]),y=JSON.parse('{"path":"/community/contributions/marwie/usdz-hide-object-on-start","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/marwie: usdz hide object on start.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{g as comp,y as data}; diff --git a/assets/vanilla-js.html-DtAi2Rtr.js b/assets/vanilla-js.html-DtAi2Rtr.js new file mode 100644 index 000000000..2830dc7a8 --- /dev/null +++ b/assets/vanilla-js.html-DtAi2Rtr.js @@ -0,0 +1 @@ +import{_ as n,r as o,o as a,c as i,a as l,d as s,b as r}from"./app-CRZRGfEE.js";const d={};function c(m,e){const t=o("RouteLink");return a(),i("div",null,[l("p",null,[e[0]||(e[0]=s("Moved to ")),r(t,{to:"/getting-started/"})])])}const p=n(d,[["render",c],["__file","vanilla-js.html.vue"]]),v=JSON.parse('{"path":"/vanilla-js.html","title":"Using Needle Engine directly from HTML","lang":"en-US","frontmatter":{"title":"Using Needle Engine directly from HTML","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/using needle engine directly from html.png"}],["meta",{"name":"og:description","content":"---\\nMoved to [](./getting-started/)"}]],"description":"---\\nMoved to [](./getting-started/)"},"headers":[],"git":{"updatedTime":1727182460000},"filePathRelative":"vanilla-js.md"}');export{p as comp,v as data}; diff --git a/assets/vertical-move-in-vr-using-the-right-joystick-quest.html-4yb7LuOj.js b/assets/vertical-move-in-vr-using-the-right-joystick-quest.html-4yb7LuOj.js new file mode 100644 index 000000000..0dc9bfec6 --- /dev/null +++ b/assets/vertical-move-in-vr-using-the-right-joystick-quest.html-4yb7LuOj.js @@ -0,0 +1,59 @@ +import{_ as t,r as n,o as h,c as k,a as i,b as l,e as p}from"./app-CRZRGfEE.js";const e={};function r(d,s){const a=n("contribution-header");return h(),k("div",null,[s[0]||(s[0]=i("p",null,[i("a",{href:"/docs/community/contributions"},"Overview")],-1)),l(a,{url:"https://github.com/Web3Kev",author:"Web3Kev",page:"/docs/community/contributions/web3kev",profileImage:"https://avatars.githubusercontent.com/u/106066970?s=100&v=4",githubUrl:"https://github.com/needle-tools/needle-engine-support/discussions/158",title:"Vertical Move in VR using the right joystick (Quest)",gradient:"True"}),s[1]||(s[1]=p(`

    The following code will enable Quest users (haven't tested with other devices) to move up and down with the right-joystick\`s y axis. (the x axis being used for snap-turns).

    This code will interfere with the teleport script when accidentally pointing towards an object and trying to move up. It is recommended to remove the teleport script for that matter.

    You can place this script anywhere.

    
    +import { Behaviour, WebXR, GameObject} from "@needle-tools/engine";
    +import { Vector3,Quaternion} from "three";
    +import { Mathf } from "@needle-tools/engine";
    +
    +export class VerticalMove extends Behaviour {
    +
    +    private webXR?: WebXR;
    +    private joystickY?:number;
    +    private worldRot: Quaternion = new Quaternion();
    +
    +    start(): void {
    +
    +        let _webxr=GameObject.findObjectOfType(WebXR);
    +        if(_webxr)
    +        {
    +            this.webXR=_webxr;
    +            console.log("webxr found");
    +        }
    +    }
    +
    +
    +    update()
    +    {
    +        if(this.context.isInVR)
    +        {
    +            //get y value from right joystick
    +            this.verticalMove();
    +        }
    +    }
    +
    +    verticalMove():void
    +    {
    +        if(this.webXR?.RightController?.input?.gamepad?.axes[3]) 
    +        {
    +            this.joystickY=this.webXR.RightController.input.gamepad.axes[3];
    +
    +            const speedFactor = 3;
    +            const powFactor = 2;
    +            const speed = Mathf.clamp01(2 * 2);
    +            
    +            const verticalDir = this.joystickY < 0 ? 1 : -1;
    +            let vertical = Math.pow(this.joystickY, powFactor);
    +            vertical *= verticalDir;
    +            vertical *= speed;
    +
    +            this.webXR.Rig.getWorldQuaternion(this.worldRot);
    +            
    +            let movementVector=new Vector3();
    +            movementVector.set(0, vertical, 0);
    +            movementVector.applyQuaternion(this.webXR.TransformOrientation);
    +            movementVector.x = 0;
    +            movementVector.applyQuaternion(this.worldRot);
    +            movementVector.multiplyScalar(speedFactor * this.context.time.deltaTime);
    +
    +            this.webXR.Rig.position.add(movementVector);
    +        }
    +    }
    +}
    `,4))])}const g=t(e,[["render",r],["__file","vertical-move-in-vr-using-the-right-joystick-quest.html.vue"]]),y=JSON.parse('{"path":"/community/contributions/web3kev/vertical-move-in-vr-using-the-right-joystick-quest","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/web3kev: vertical move in vr using the right joystick quest.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{g as comp,y as data}; diff --git a/assets/video-embed-Dnh8jbMt.js b/assets/video-embed-Dnh8jbMt.js new file mode 100644 index 000000000..40286580a --- /dev/null +++ b/assets/video-embed-Dnh8jbMt.js @@ -0,0 +1 @@ +import{_ as n,o as t,c as r,a,u as l}from"./app-CRZRGfEE.js";const _={props:{src:String,controls:Boolean,limit_height:Boolean,max_height:String}},o=_,i=()=>{l(e=>({"50c06be4":e.limit_height?"auto":"100%",22327078:e.limit_height?"100%":"auto","6af71086":e.limit_height?e.max_height:"100%"}))},c=o.setup;o.setup=c?(e,s)=>(i(),c(e,s)):i;const d={key:0,class:"container"},p=["src"],h={key:1,class:"container"},u=["src"];function m(e,s,f,g,v,b){return e.src.includes("youtube.com")?(t(),r("div",d,[a("iframe",{id:"ytplayer",class:"video",src:e.src.replace("watch?v=","embed/")+"?autoplay=0&origin=http://docs.needle.tools&controls=1&loop=1&modestbranding=1&showinfo=0&color=white&rel=0",frameborder:"0",allowfullscreen:""},null,8,p)])):(t(),r("div",h,[a("video",{loop:"",autoplay:"",controls:"",src:e.src},null,8,u)]))}const B=n(o,[["render",m],["__scopeId","data-v-977b38fe"],["__file","video-embed.vue"]]);export{B as default}; diff --git a/assets/vision.html-zI-oAntf.js b/assets/vision.html-zI-oAntf.js new file mode 100644 index 000000000..b060d40e6 --- /dev/null +++ b/assets/vision.html-zI-oAntf.js @@ -0,0 +1 @@ +import{_ as o,r as a,o as r,c as s,e as t,a as i,b as l,w as d,d as h}from"./app-CRZRGfEE.js";const p={};function c(g,e){const n=a("RouteLink");return r(),s("div",null,[e[1]||(e[1]=t('

    Our Vision ๐Ÿ”ฎ

    The Future of the 3D Web

    We believe the use of 3D on the web will expand considerably in the next years. While today native apps are the norm, more and more content is made available as a web app or PWA. New VR and AR devices will extend into the web, creating an interesting problem: responsive suddenly not only means "small screen" or "large screen", you're also dealing with spaces, 3D, spatial placement and potentially glasses and controllers!

    Add to that a push towards more interactivity and collaboration, and you have an interesting mix of challenges.

    At Needle, we believe ideating and creating in this space should be easy. We've set out to speed things up โ€“ creating our own runtime to reach these goals. That's why we're baking the ability to deploy to AR and VR right into our core components, and continually test that new ideas work across platforms.

    Why another platform for 3D on the web? Aren't there enough options already?

    There's numerous options, that's true! We found that current systems1 can be roughly sorted into two categories: some have great asset handling, tools, and artist-friendly workflows but output some sort of binary blob, and others are more code-focussed, developer-friendly and allow for great integration into modern web workflows2.

    We want to bridge these worlds and combine the best of both worlds: artist-friendly workflows and modern web technologies. Combined with modern formats and a snappy workflow, we believe this will allow many more creators to bring their content to the web. We also saw an opportunity to get AR, VR and collaboration right from the start.

    1: Examples include Unity, PlayCanvas, three.js, react-three-fiber, Babylon, A-Frame, Godot, and many more.2: There's more nuance to this than fits into an introductory paragraph! All engines and frameworks have their strengths and weaknesses, and are constantly evolving.

    Creating a Workflow, not an Editor

    We think the next wave of 3D apps on the web will come with better workflows: everyone should be able to put together a 3D scene, an art gallery, present a product or 3D scan on the web or make simple games. Reaching this goal will require more than just supporting one particular system and exporting to the web from there.

    Our goal is to allow people to bring data to the web from their creative tools: be it Unity, Blender, Photoshop, or something else. We're aware that this is a big goal โ€“ but instead of doing everything at once, we want to iterate and get closer to it together.

    Open Standards instead of Proprietary Containers

    At the core of Needle Engine stands the glTF format and its ability to be extended with custom extensions. The goal is: a single .glb file can contain your entire application's data.

    It's worth noting that it's not a goal to ship actual code inside glTF; shipping and running code is the job of modern web runtimes and bundling. We certainly can imagine that abstract representations of logic (e.g. graphs, state machines, and so on) can be standardized to a certain degree and allow for interoperable worlds, but we're not there yet.

    ',15)),i("p",null,[l(n,{to:"/technical-overview.html"},{default:d(()=>e[0]||(e[0]=[h("Read more about our use of glTF and extensions")])),_:1})]),e[2]||(e[2]=t('

    Goals and Non-Goals

    Goals

    • Iteration should be rapid and deployment should be fast.
    • Working on 3D web projects should be the as easy as working 2D web projects.
    • Developers and artists should be able to collaborate directly.
    • Responsive web extends beyond screens โ€“ AR and VR should be built in, not afterthoughts.
    • We want to contribute back to open-source projects.
    • Open discussion regarding 3D and web standards.
    • Ability to bring and take your data in open formats.
    • Ability to choose what web framework you use, not lock-in to particular frameworks and vendors.
    • Common usecases work without or with limited coding experience.

    Non-Goals

    • It's not a goal to have 100% coverage of all combinations of Editor versions, feature sets, render pipelines.
    • It's not a goal to provide a full no-code environment.
    • It's not a goal to match the feature set, capabilities, or runtime performance of other engines.

    Relation to other engines and frameworks

    Needle Engine and Unity WebGL

    From working with Unity for many years we've found that while the engine and editor progress at a great pace, WebGL output has somewhat lacked behind. Integration of Unity players into web-based systems is rather hard, "talking" to the surrounding website requires a number of workarounds, and most of all, iteration times are very slow due to the way that Unity packs all code into WebAssembly via IL2CPP. These technologies are awesome, and result in great runtime performance and a lot of flexibility. But they're so much slower and walled off compared to modern web development workflows that we decided to take matters into our own hands.

    Needle Engine and three.js

    Needle Engine builds on three.js. All rendering goes through it, glTF files are loaded via three's extension interfaces, and our component system revolves around three's Object3D and scene graph. We're committed to upstreaming some of our changes and improvements, creating pull requests and reporting issues along the way.

    ',10))])}const w=o(p,[["render",c],["__file","vision.html.vue"]]),m=JSON.parse(`{"path":"/vision.html","title":"Our Vision ๐Ÿ”ฎ","lang":"en-US","frontmatter":{"next":"features-overview","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/vision.png"}],["meta",{"name":"og:description","content":"---\\nWe believe the use of 3D on the web will expand considerably in the next years. While today native apps are the norm, more and more content is made available as a web app or PWA. New VR and AR devices will extend into the web, creating an interesting problem: responsive suddenly not only means 'small screen' or 'large screen', you're also dealing with spaces, 3D, spatial placement and potentially glasses and controllers!\\nAdd to that a push towards more interactivity and collaboration, and you have an interesting mix of challenges.\\nAt Needle, we believe ideating and creating in this space should be easy. We've set out to speed things up โ€“ creating our own runtime to reach these goals. That's why we're baking the ability to deploy to AR and VR right into our core components, and continually test that new ideas work across platforms.\\nThere's numerous options, that's true! We found that current systems1 can be roughly sorted into two categories: some have great asset handling, tools, and artist-friendly workflows but output some sort of binary blob, and others are more code-focussed, developer-friendly and allow for great integration into modern web workflows2.\\nWe want to bridge these worlds and combine the best of both worlds: artist-friendly workflows and modern web technologies. Combined with modern formats and a snappy workflow, we believe this will allow many more creators to bring their content to the web. We also saw an opportunity to get AR, VR and collaboration right from the start.\\n1: _Examples include Unity, PlayCanvas, three.js, react-three-fiber, Babylon, A-Frame, Godot, and many more._\\n2: _There's more nuance to this than fits into an introductory p"}]],"description":"---\\nWe believe the use of 3D on the web will expand considerably in the next years. While today native apps are the norm, more and more content is made available as a web app or PWA. New VR and AR devices will extend into the web, creating an interesting problem: responsive suddenly not only means 'small screen' or 'large screen', you're also dealing with spaces, 3D, spatial placement and potentially glasses and controllers!\\nAdd to that a push towards more interactivity and collaboration, and you have an interesting mix of challenges.\\nAt Needle, we believe ideating and creating in this space should be easy. We've set out to speed things up โ€“ creating our own runtime to reach these goals. That's why we're baking the ability to deploy to AR and VR right into our core components, and continually test that new ideas work across platforms.\\nThere's numerous options, that's true! We found that current systems1 can be roughly sorted into two categories: some have great asset handling, tools, and artist-friendly workflows but output some sort of binary blob, and others are more code-focussed, developer-friendly and allow for great integration into modern web workflows2.\\nWe want to bridge these worlds and combine the best of both worlds: artist-friendly workflows and modern web technologies. Combined with modern formats and a snappy workflow, we believe this will allow many more creators to bring their content to the web. We also saw an opportunity to get AR, VR and collaboration right from the start.\\n1: _Examples include Unity, PlayCanvas, three.js, react-three-fiber, Babylon, A-Frame, Godot, and many more._\\n2: _There's more nuance to this than fits into an introductory p"},"headers":[{"level":2,"title":"The Future of the 3D Web","slug":"the-future-of-the-3d-web","link":"#the-future-of-the-3d-web","children":[]},{"level":2,"title":"Why another platform for 3D on the web? Aren't there enough options already?","slug":"why-another-platform-for-3d-on-the-web-aren-t-there-enough-options-already","link":"#why-another-platform-for-3d-on-the-web-aren-t-there-enough-options-already","children":[]},{"level":2,"title":"Creating a Workflow, not an Editor","slug":"creating-a-workflow-not-an-editor","link":"#creating-a-workflow-not-an-editor","children":[]},{"level":2,"title":"Open Standards instead of Proprietary Containers","slug":"open-standards-instead-of-proprietary-containers","link":"#open-standards-instead-of-proprietary-containers","children":[]},{"level":2,"title":"Goals","slug":"goals","link":"#goals","children":[]},{"level":2,"title":"Non-Goals","slug":"non-goals","link":"#non-goals","children":[]},{"level":2,"title":"Needle Engine and Unity WebGL","slug":"needle-engine-and-unity-webgl","link":"#needle-engine-and-unity-webgl","children":[]},{"level":2,"title":"Needle Engine and three.js","slug":"needle-engine-and-three.js","link":"#needle-engine-and-three.js","children":[]}],"git":{"updatedTime":1667075212000},"filePathRelative":"vision.md"}`);export{w as comp,m as data}; diff --git a/assets/web3kev.html-BYOJlV9Z.js b/assets/web3kev.html-BYOJlV9Z.js new file mode 100644 index 000000000..5229fa0e6 --- /dev/null +++ b/assets/web3kev.html-BYOJlV9Z.js @@ -0,0 +1,466 @@ +import{_ as e,r as a,o as r,c as p,b as k,w as t,a as i,d as s}from"./app-CRZRGfEE.js";const C={};function d(y,h){const l=a("contribution-preview"),n=a("contributions-author");return r(),p("div",null,[k(n,{overviewLink:"/docs/community/contributions",name:"Web3Kev",url:"https://github.com/Web3Kev",profileImage:"https://avatars.githubusercontent.com/u/106066970?s=100&v=4",githubUrl:"https://github.com/Web3Kev"},{default:t(()=>[k(l,{title:"Vertical Move in VR using the right joystick (Quest)",pageUrl:"/docs/community/contributions/web3kev/vertical-move-in-vr-using-the-right-joystick-quest"},{default:t(()=>h[0]||(h[0]=[i("p",null,"The following code will enable Quest users (haven't tested with other devices) to move up and down with the right-joystick`s y axis. (the x axis being used for snap-turns).",-1),i("p",null,"This code will interfere with the teleport script when accidentally pointing towards an object and trying to move up. It is recommended to remove the teleport script for that matter.",-1),i("p",null,"You can place this script anywhere.",-1),i("div",{class:"language-ts","data-highlighter":"shiki","data-ext":"ts","data-title":"ts",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[i("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[i("code",null,[i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Behaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," WebXR"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," GameObject"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "@needle-tools/engine"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Vector3"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Quaternion"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "three"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Mathf "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "@needle-tools/engine"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"export"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," class"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," VerticalMove"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," extends"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Behaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," webXR"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?:"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," WebXR"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," joystickY"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?:"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"number"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," worldRot"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Quaternion "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6","--shiki-light-font-weight":"bold","--shiki-dark-font-weight":"bold"}}," new"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Quaternion"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," start"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," void"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," let"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," _webxr"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"GameObject"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"findObjectOfType"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(WebXR)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(_webxr)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"webXR"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"_webxr"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," console"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"log"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"webxr found"'),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," update"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"context"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"isInVR)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //get y value from right joystick")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"verticalMove"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," verticalMove"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"void")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"webXR"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"RightController"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"input"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"gamepad"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"axes["),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"3"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"]) ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"joystickY"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"webXR"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"RightController"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"input"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"gamepad"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"axes["),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"3"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"]"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," speedFactor "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 3"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," powFactor "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 2"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," speed "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Mathf"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"clamp01"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"2"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," *"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 2"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," verticalDir "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"joystickY "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"<"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 0"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," ?"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 1"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," :"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," -"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"1"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," let"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," vertical "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Math"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"pow"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"joystickY"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," powFactor)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," vertical "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"*="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," verticalDir"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," vertical "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"*="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," speed"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"webXR"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Rig"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"getWorldQuaternion"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"worldRot)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," let"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," movementVector"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6","--shiki-light-font-weight":"bold","--shiki-dark-font-weight":"bold"}},"new"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Vector3"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," movementVector"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"set"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," vertical"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 0"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," movementVector"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"applyQuaternion"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"webXR"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"TransformOrientation)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," movementVector"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"x "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 0"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," movementVector"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"applyQuaternion"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"worldRot)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," movementVector"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"multiplyScalar"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(speedFactor "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"*"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"context"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"time"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"deltaTime)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"webXR"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Rig"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"position"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"add"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(movementVector)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}")])])])],-1)])),_:1}),k(l,{title:"Squeeze to Scale (Object or World) in VR",pageUrl:"/docs/community/contributions/web3kev/squeeze-to-scale-object-or-world-in-vr"},{default:t(()=>h[1]||(h[1]=[i("p",null,"The following code enables you to use both controllers in VR (tested on Quest) and scale the player's perspective (XRRig) by squeezing the grab triggers and moving the controllers closer (pinch out) or further apart (pinch in). The boolean allowWorldScaling has to be ticked in unity for that to work.",-1),i("p",null,"Upon selecting a draggable object (Drag controls script), the player can scale up or down that object, while keeping the finger on the trigger and squeezing both grab buttons and moving the hands closer or apart.",-1),i("p",null,"The current script enables you to visually see the scale. Create a world canvas with a text component as a child. Assign the world canvas to scaleTextObject and the text to scaleText. scaleTextObject will then spawn in front of the player and follow the head movement whenever scaling.",-1),i("p",null,"At the moment the position of the hands (controllers) is done by finding the avatar's hands. I couldn't make it work otherwise. If you find a better way please share.",-1),i("div",{class:"language-ts","data-highlighter":"shiki","data-ext":"ts","data-title":"ts",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[i("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[i("code",null,[i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Behaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," WebXR"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"serializeable"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," WebXREvent"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"WebXRAvatar"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"GameObject"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," AvatarMarker"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Text"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "@needle-tools/engine"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Object3D"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Vector3"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Quaternion"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"PerspectiveCamera"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "three"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"export"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," class"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," SqueezeScale"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," extends"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Behaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," webXR"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?:"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," WebXR"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," selectedObj"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Object3D"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"|"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," null"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," ="),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," null"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," @serializeable"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"("),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Object3D"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," scaleTextObject"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Object3D"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"|"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," null"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," ="),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," null"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," @serializeable"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"("),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Text"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," scaleText"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?:"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Text"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," public"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," allowWorldScaling"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," boolean"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," ="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"false"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," leftSqueeze"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"boolean"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"false"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," rightSqueeze"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"boolean"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"false"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," bothSqueezeStarted"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"false"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," rigScaleUpdated"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"false"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," initialDistance"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"number"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"1"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," initialScale"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"number"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"1"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," newScale"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"number"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," |"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," null"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"null"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," leftHand"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?:"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"Object3D"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," rightHand"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?:"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"Object3D"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," head"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?:"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"Object3D"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," start"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," void"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," let"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," _webxr"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"GameObject"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"findObjectOfType"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(WebXR)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(_webxr)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"webXR"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"_webxr"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," console"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"log"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"webxr found"'),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //Wait for XR Session")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," WebXR"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"addEventListener"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(WebXREvent"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"XRStarted"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," ()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," =>"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //listen to squeeze events")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"context"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"xrSession"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"addEventListener"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"squeezestart"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," ("),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"event"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},")"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," =>"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"onSqueezeEvent"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(event"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"true"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"context"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"xrSession"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"addEventListener"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"squeezeend"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," ("),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"event"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},")"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," =>"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"onSqueezeEvent"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(event"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"false"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," onSqueezeEvent"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"("),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"event"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," XRInputSourceEvent"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," status"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"boolean"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(event"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"inputSource"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"handedness"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"==="),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"right"'),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"rightSqueeze"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"status"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(event"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"inputSource"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"handedness"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"==="),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"left"'),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"leftSqueeze"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"status"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," update"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"(){")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"context"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"isInVR)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //cache object selected if any")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"objectGrab"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //if both grips are squeezed ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"leftSqueeze "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"&&"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"rightSqueeze)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //if object is selected either in the left or right controller (only one)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"selectedObj"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"!="),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"null"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //after initial distance value has been set")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"bothSqueezeStarted)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //get current distance between controllers")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," scaleValue"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"calculateDistance"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},' //get distance change since beginning of squeeze to get a "pinch in/out" effect')]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"newScale"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"initialScale"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"+"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"scaleValue"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"-"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"initialDistance"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //avoid 0 and negative scales")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"newScale"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"<"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0.001"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"newScale"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0.001"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";}")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," // scale object according to new distance since initial distance")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"selectedObj"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"scale"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"x"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"newScale"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"selectedObj"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"scale"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"y"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"newScale"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"selectedObj"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"scale"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"z"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"newScale"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"showVisual"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"newScale"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"Object :"'),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," else")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //get initial distance value (only once at a new squeeze both hands event)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"bothSqueezeStarted"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"true"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"initialDistance"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"calculateDistance"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //cache object's initial scale")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"initialScale"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"selectedObj"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"scale"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"x"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," else")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //scale world ?")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"webXR"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Rig "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"&&"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"allowWorldScaling)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //after initial distance value has been set")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"bothSqueezeStarted)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //get current distance between controllers")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," scaleValue"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"calculateDistance"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},' //get distance change since beginning of squeeze to get a "pinch in/out" effect')]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"newScale"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"initialScale"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"+"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"scaleValue"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"-"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"initialDistance"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //avoid 0 and negative scales")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"newScale"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"<"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0.001"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"newScale"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0.001"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";}")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"showVisual"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"newScale"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "World :"'),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"rigScaleUpdated"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"true"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," else")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //get initial distance value (only once at a new squeeze both hands event)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"bothSqueezeStarted"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"true"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"initialDistance"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"calculateDistance"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //cache object's initial scale")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"initialScale"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"webXR"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Rig"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"scale"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"x"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," else")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //reset values")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"bothSqueezeStarted"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"false"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //if world has been scaled, scale rig accordingly at the end of squeezing and once only")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"webXR"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Rig "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"&&"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"rigScaleUpdated "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"&&"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"newScale)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //change rig scale")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"webXR"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Rig"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"scale"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"set"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"newScale"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"newScale"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"newScale)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"webXR"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Rig"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"updateMatrixWorld"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," cam "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"context"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"mainCamera "),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"as"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," PerspectiveCamera"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," cam"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"near"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"newScale"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},">"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"2"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0.0001"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0.2"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," cam"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"updateProjectionMatrix"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //reset")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"rigScaleUpdated"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"false"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"scaleTextObject)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"scaleTextObject"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"visible"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"false"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"newScale"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"null"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," calculateDistance"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"number")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," let"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," distance"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"1"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"leftHand "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"&&"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"rightHand)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," left"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"leftHand"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"position"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," right"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"rightHand"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"position"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," // Calculate the difference between the positions")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," dx "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," left"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"x "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"-"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," right"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"x"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," dy "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," left"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"y "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"-"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," right"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"y"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," dz "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," left"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"z "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"-"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," right"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"z"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," // Calculate the distance using the Euclidean distance formula")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," distance "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Math"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"sqrt"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(dx "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"*"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," dx "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"+"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," dy "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"*"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," dy "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"+"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," dz "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"*"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," dz)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," else")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //set positions of controllers from your avatar (only once)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," let"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," allAvatars "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," AvatarMarker"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"instances"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(allAvatars"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"length"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},">"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," for"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ("),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"let"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," i"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"i"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"<"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"allAvatars"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"length"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"i"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"++"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(allAvatars[i]"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"isLocalAvatar"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"())")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," av"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"allAvatars[i]"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"avatar "),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"as"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," WebXRAvatar"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(av"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"!="),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"null"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"leftHand"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"av"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"handLeft "),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"as"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Object3D"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"rightHand"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"av"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"handRight "),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"as"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Object3D"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"head "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," av"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"head "),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"as"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Object3D"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," return"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," distance"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," showVisual"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"("),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"scale"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"number"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," mesg"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"string"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},")"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"void")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"scaleTextObject "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"&&"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"head "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"&&"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"scaleText)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"scaleTextObject"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"visible"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"true"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," offset "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6","--shiki-light-font-weight":"bold","--shiki-dark-font-weight":"bold"}}," new"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Vector3"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"7"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," offset"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"applyQuaternion"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"head"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"quaternion)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"scaleTextObject"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"position"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"copy"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"head"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"position"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"add"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(offset))"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," roundedNum"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," +"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"scale"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"toFixed"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"3"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"scaleText"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"text"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"mesg"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"+"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'" "'),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"+"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"roundedNum"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," objectGrab"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"void")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"webXR"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"RightController"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"grabbed"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"selected) ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"selectedObj "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"webXR"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"RightController"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"grabbed"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"selected"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," else"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"webXR"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"LeftController"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"grabbed"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"selected)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"selectedObj "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"webXR"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"LeftController"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"grabbed"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"selected"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," else")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"selectedObj"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"null"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}")])])])],-1)])),_:1}),k(l,{title:"Network instantiation of multiple objects",pageUrl:"/docs/community/contributions/web3kev/network-instantiation-of-multiple-objects"},{default:t(()=>h[2]||(h[2]=[i("p",null,"In a multiuser session, typically objects are instantiated using instantiateSynced as such:",-1),i("div",{class:"language-ts","data-highlighter":"shiki","data-ext":"ts","data-title":"ts",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[i("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[i("code",null,[i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Behaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"GameObject"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"serializable"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"InstantiateOptions"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "@needle-tools/engine"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Vector3"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Object3D"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "three"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"export"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," class"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," InstantiateObjectForAll"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," extends"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Behaviour")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," @serializable"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"("),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Object3D"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," myPrefab"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?:"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," GameObject"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," public"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," makeObject"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"void"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," options "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6","--shiki-light-font-weight":"bold","--shiki-dark-font-weight":"bold"}}," new"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," InstantiateOptions"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," options"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"context "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"context"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," options"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"position "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6","--shiki-light-font-weight":"bold","--shiki-dark-font-weight":"bold"}}," new"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Vector3"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," GameObject"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"instantiateSynced"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"myPrefab"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," options) "),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"as"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," GameObject"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}")])])])],-1),i("p",null,"My particular use-case was for generating programmatically a random scene made of cubes, and that scene had to be the same for all users of the same room. I had used the example above but for some unknown reasons sometimes the scenes were partially rendered when instantiating simultaneously >400 objects. @Marcel of Needle suggested to generate a seed (position of all objects in the scene) and send that seed instead using :",-1),i("div",{class:"language-ts","data-highlighter":"shiki","data-ext":"ts","data-title":"ts",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[i("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[i("code",null,[i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"context"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"connection"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"send"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()")])])])],-1),i("p",null,"All users using :",-1),i("div",{class:"language-ts","data-highlighter":"shiki","data-ext":"ts","data-title":"ts",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[i("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[i("code",null,[i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"context"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"connection"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"beginListen"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()")])])])],-1),i("p",null,"would receive any seed previously sent, upon joining the same room, allowing them to instantiate cubes according to that seed (array of Vector3).",-1),i("p",null,"Here is a script illustrating the use of the send method and the beginListen counterpart:",-1),i("div",{class:"language-ts","data-highlighter":"shiki","data-ext":"ts","data-title":"ts",style:{"--shiki-light":"#4c4f69","--shiki-dark":"#c6d0f5","--shiki-light-bg":"#eff1f5","--shiki-dark-bg":"#303446"}},[i("pre",{class:"shiki shiki-themes catppuccin-latte catppuccin-frappe vp-code"},[i("code",null,[i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"//This is an example of sending the seed of a randomly generated scene made of cubes, for all other instances logging into the same room to create the same scene.")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"//This script requires a prefab (e.g. a 1x1x1 Cube)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"//This script will generate and build randomly positioned cubes (random walk) as a child of the object it is attached to. ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"//The generateSeed() method is in this script called via a button. The button is deactivated once the seed has been transmitted.")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"//Any users joining the same room will receive the seed and build the exact same scene")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Behaviour"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"GameObject"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"serializable"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"InstantiateOptions"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "@needle-tools/engine"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"import"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Vector3"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Object3D "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," from"),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},' "three"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"export"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," class"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," NetworkedSeed"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," extends"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Behaviour")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," @serializable"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"("),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Object3D"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," prefab"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?:"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," GameObject"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," @serializable"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"("),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"Object3D"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," generateButton"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"?:"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Object3D"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," public"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," seedSize"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," number"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," ="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 30"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," seed"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Vector3[] "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," []"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," onEnable"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," void"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"context"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"connection"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"beginListen"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"mySeed"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"onDataReceived)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"generateButton)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"generateButton"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"visible"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"true"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," onDisable"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," void"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"context"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"connection"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"stopListen"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"mySeed"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"onDataReceived)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," onDataReceived"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," ="),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," ("),i("span",{style:{"--shiki-light":"#E64553","--shiki-dark":"#EA999C","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"data"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," any"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},")"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," =>"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," console"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"log"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"Received data:"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," data"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"mySeed)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"seed"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"length"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"==="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //prevent other generations of the seed")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"generateButton)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"generateButton"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"visible"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"false"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"seed"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"data"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"mySeed"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //build scene")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"buildScene"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," };")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //generate and send seed to all from the button generateButton")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," public"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," generateSeed"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"void"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"seed"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"length"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"=="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},") "),i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"//no seed found => generate one")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"seed "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," []"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," uniquePositions "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6","--shiki-light-font-weight":"bold","--shiki-dark-font-weight":"bold"}}," new"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Set"),i("span",{style:{"--shiki-light":"#04A5E5","--shiki-dark":"#99D1DB"}},"<"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"string"),i("span",{style:{"--shiki-light":"#04A5E5","--shiki-dark":"#99D1DB"}},">"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //start at origin")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," startPosition "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6","--shiki-light-font-weight":"bold","--shiki-dark-font-weight":"bold"}}," new"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Vector3"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 0"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 0"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"seed"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"push"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(startPosition"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"clone"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"())"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," uniquePositions"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"add"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(startPosition"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"toArray"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"toString"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"())"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //go for a random walk of length : seedSize")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," while"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"seed"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"length "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"<"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"seedSize) "),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," lastPosition "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"seed["),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"seed"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"length "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"-"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 1"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"]"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," let"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," newPosition"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Vector3"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //walk and add position, making sure they are unique")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," do"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," direction "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"getRandomDirection"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," newPosition "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," lastPosition"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"clone"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"add"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(direction)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," while"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," (uniquePositions"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"has"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(newPosition"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"toArray"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"toString"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()))"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"seed"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"push"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(newPosition"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"clone"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"())"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," uniquePositions"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"add"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(newPosition"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"toArray"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"toString"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"())"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //send the seed to all on the server")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"sendSeed"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //prevent other generations of the seed")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"generateButton)")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"generateButton"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"visible"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"false"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //build scene locally")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"buildScene"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," sendSeed"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"void"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"seed"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"length"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"!="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"context"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"connection"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"send"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"mySeed"'),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},",{"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"guid"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"guid"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," mySeed"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"seed"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," console"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"log"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"------ SEED SENT -------"'),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," public"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," buildScene"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"void"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"{")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //check if the seed is not empty")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"seed"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"length"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"=="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," console"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"log"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"array was empty"'),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," return"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," //check if the scene has already been built")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"gameObject"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"children"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"length"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},">"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},") ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," console"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"log"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"Scene already present"'),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," return"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#9CA0B0","--shiki-dark":"#737994","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," // Create cubes at each position of the random walk ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," for"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"let"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," i"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"0"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," i"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"<"),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"seed"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"length"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," i"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"++"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," option "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6","--shiki-light-font-weight":"bold","--shiki-dark-font-weight":"bold"}}," new"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," InstantiateOptions"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"()"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," option"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"context "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"context"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," option"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"parent"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"gameObject"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," option"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"position "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}}," this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"seed[i]"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," if"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"prefab"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"!="),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"null"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," cube "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," GameObject"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"instantiate"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#D20F39","--shiki-dark":"#E78284"}},"this"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"prefab"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," option) "),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}},"as"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," GameObject"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," console"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"log"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"("),i("span",{style:{"--shiki-light":"#40A02B","--shiki-dark":"#A6D189"}},'"----------- Scene Built ---------"'),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},")"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," ")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," private"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," getRandomDirection"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"()"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},":"),i("span",{style:{"--shiki-light":"#DF8E1D","--shiki-dark":"#E5C890","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Vector3"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," {")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," x "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Math"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"random"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"() "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"<"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 0.5"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," ?"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," -"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"1"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," :"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 1"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," y "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Math"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"random"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"() "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"<"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 0.5"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," ?"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," -"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"1"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," :"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 1"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," const"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," z "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"="),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," Math"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"."),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}},"random"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"() "),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}},"<"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 0.5"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," ?"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," -"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}},"1"),i("span",{style:{"--shiki-light":"#179299","--shiki-dark":"#81C8BE"}}," :"),i("span",{style:{"--shiki-light":"#FE640B","--shiki-dark":"#EF9F76"}}," 1"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6"}}," return"),i("span",{style:{"--shiki-light":"#8839EF","--shiki-dark":"#CA9EE6","--shiki-light-font-weight":"bold","--shiki-dark-font-weight":"bold"}}," new"),i("span",{style:{"--shiki-light":"#1E66F5","--shiki-dark":"#8CAAEE","--shiki-light-font-style":"italic","--shiki-dark-font-style":"italic"}}," Vector3"),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}},"(x"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," y"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},","),i("span",{style:{"--shiki-light":"#4C4F69","--shiki-dark":"#C6D0F5"}}," z)"),i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},";")]),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}}," }")]),s(` +`),i("span",{class:"line"}),s(` +`),i("span",{class:"line"},[i("span",{style:{"--shiki-light":"#7C7F93","--shiki-dark":"#949CBB"}},"}")])])])],-1),i("p",null,"The above script is placed on an object (any Transform) and will generate an array of unique Vector3 positions for a specified length (seedSize) after generateSeed() is called (In this case it is called from a button: generateButton).",-1),i("p",null,"Once generated it will send the array to the server and build the scene. The building process consist of instantiating the prefab at each Vector3 position of the seed (this.seed) array.",-1),i("p",null,"Any user joining the same room after a seed has been generated and sent, will receive the seed from the server and trigger the callback onDataReceived() which will cache the seed array, disable the button, and build the scene with the prefab, according to the seed.",-1),i("p",null,"This gives a way to generate a scene and communicate the seed of that scene, for each user to build locally.",-1),i("p",null,"This was the solution I chose which worked better than instantiating a complex scene (>400 objects) with instantiateSynced which would occasionally cause bugs.",-1)])),_:1})]),_:1})])}const F=e(C,[["render",d],["__file","web3kev.html.vue"]]),E=JSON.parse('{"path":"/community/contributions/web3kev","title":"","lang":"en-US","frontmatter":{"head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/contributions: web3kev.png"}],["meta",{"name":"og:description","content":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."}]],"description":"Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally. Needle Exporter for Unity bridges the Unity Editor and the web runtime. It helps you to export your assets, animations, lightmaps and so on to the web. It is built around the glTF standard for 3D assets."},"headers":[],"git":{},"filePathRelative":null}');export{F as comp,E as data}; diff --git a/assets/xr.html-BFJdLi8t.js b/assets/xr.html-BFJdLi8t.js new file mode 100644 index 000000000..214fe85b5 --- /dev/null +++ b/assets/xr.html-BFJdLi8t.js @@ -0,0 +1,14 @@ +import{_ as d,r as o,o as p,c as h,e as a,a as t,d as s,b as i,w as r}from"./app-CRZRGfEE.js";const c={};function u(g,e){const n=o("RouteLink"),l=o("sample");return p(),h("div",null,[e[34]||(e[34]=a('

    Supported Devices

    Theoretically all WebXR-capable devices and browsers should be supported. That being said, we've tested the following configurations:

    Tested VR DeviceBrowserNotes
    Apple Vision Proโœ”๏ธ Safari Browserhand tracking, support for transient pointer
    Meta Quest 1โœ”๏ธ Meta Browserhand tracking, support for sessiongranted1
    Meta Quest 2โœ”๏ธ Meta Browserhand tracking, support for sessiongranted1, passthrough (black and white)
    Meta Quest 3โœ”๏ธ Meta Browserhand tracking, support for sessiongranted1, passthrough, depth sensing, mesh tracking
    Meta Quest Proโœ”๏ธ Meta Browserhand tracking, support for sessiongranted1, passthrough
    Pico Neo 3โœ”๏ธ Pico Browserno hand tracking, inverted controller thumbsticks
    Pico Neo 4โœ”๏ธ Pico Browserpassthrough, hand tracking2
    Oculus Rift 1/2โœ”๏ธ Chrome
    Hololens 2โœ”๏ธ Edgehand tracking, support for AR and VR (in VR mode, background is rendered as well)
    Looking Glass Portraitโœ”๏ธ Chromerequires shim, see samples
    ',3)),t("table",null,[e[11]||(e[11]=t("thead",null,[t("tr",null,[t("th",null,"Tested AR Device"),t("th",null,"Browser"),t("th",null,"Notes")])],-1)),t("tbody",null,[e[5]||(e[5]=t("tr",null,[t("td",null,"Android 10+"),t("td",null,"โœ”๏ธ Chrome"),t("td")],-1)),e[6]||(e[6]=t("tr",null,[t("td",null,"Android 10+"),t("td",null,"โœ”๏ธ Firefox"),t("td")],-1)),e[7]||(e[7]=t("tr",null,[t("td",null,"iOS 15+"),t("td",null,"โœ”๏ธ WebXR Viewer"),t("td",null,"does not fully implement standards, but supported")],-1)),t("tr",null,[e[3]||(e[3]=t("td",null,"iOS 15+",-1)),e[4]||(e[4]=t("td",null,[s("(โœ”๏ธ)"),t("sup",null,"3"),s(" Safari")],-1)),t("td",null,[e[1]||(e[1]=s("No full code support, but Needle ")),i(n,{to:"/everywhere-actions.html"},{default:r(()=>e[0]||(e[0]=[s("Everywhere Actions")])),_:1}),e[2]||(e[2]=s(" are supported for creating dynamic, interactive USDZ files."))])]),e[8]||(e[8]=t("tr",null,[t("td",null,"Hololens 2"),t("td",null,"โœ”๏ธ Edge"),t("td")],-1)),e[9]||(e[9]=t("tr",null,[t("td",null,"Hololens 1"),t("td",null,"โŒ"),t("td",null,"no WebXR support")],-1)),e[10]||(e[10]=t("tr",null,[t("td",null,"Magic Leap 2"),t("td",null,"โœ”๏ธ"),t("td")],-1))])]),e[35]||(e[35]=t("table",null,[t("thead",null,[t("tr",null,[t("th",null,"Not Tested but Should Workโ„ข๏ธ"),t("th",null,"Browser"),t("th",null,"Notes")])]),t("tbody",null,[t("tr",null,[t("td",null,"Magic Leap 1"),t("td"),t("td",null,"please let us know if you tried!")])])],-1)),t("p",null,[e[13]||(e[13]=t("sup",null,"1",-1)),e[14]||(e[14]=s(": Requires enabling a browser flag: ")),e[15]||(e[15]=t("code",null,"chrome://flags/#webxr-navigation-permission",-1)),e[16]||(e[16]=t("br",null,null,-1)),e[17]||(e[17]=t("sup",null,"2",-1)),e[18]||(e[18]=s(": Requires enabling a toggle in the Developer settings")),e[19]||(e[19]=t("br",null,null,-1)),e[20]||(e[20]=t("sup",null,"3",-1)),e[21]||(e[21]=s(": Uses ")),i(n,{to:"/everywhere-actions.html"},{default:r(()=>e[12]||(e[12]=[s("Everywhere Actions")])),_:1}),e[22]||(e[22]=s(" or ")),e[23]||(e[23]=t("a",{href:"#augmented-reality-and-webxr-on-ios"},"other approaches",-1))]),e[36]||(e[36]=a('

    Examples

    Visit our Needle Engine XR Samples to try many interactive examples right now!

    Adding VR and AR capabilities to a scene

    AR, VR and networking capabilites in Needle Engine are designed to be modular. You can choose to not support any of them, or add only specific features.

    Basic capabilities

    • Enable AR and VR
      Add a WebXR component.
      Optional: you can set a custom avatar by referencing an Avatar Prefab.
      By default a very basic DefaultAvatar is assigned.

    • Enable Teleportation
      Add a TeleportTarget component to object hierarchies that can be teleported on.
      To exclude specific objects, set their layer to IgnoreRaycasting.

    Multiplayer

    • Enable Networking
      Add a SyncedRoom component.

    • Enable Desktop Viewer Sync
      Add a SyncedCamera component.

    • Enable Voice Chat
      Add a VoIP component.

    Note: these components can be anywhere inside your GltfObject hierarchy. They can also all be on the same GameObject.

    Castle Builder uses all of the above for a cross-platform multiplayer sandbox experience.
    โ€” #madebyneedle ๐Ÿ’š

    Special AR Components

    • Define the AR Session Root and Scale
      Add a WebARSessionRoot component to your root object.
      Here you can define the user scale to shrink (< 1) or enlarge (> 1) the user in relation to the scene when entering AR.

    Controlling object display for XR

    • Define whether an object is visible in Browser, AR, VR, First Person, Third Person
      Add a XR Flag component to the object you want to control. Change options on the dropdown as needed.

      Common usecases are

      • hiding floors when entering AR
      • hiding Avatar parts in First or Third Person views (e.g. first-person head shouldn't be visible).

    Travelling between VR worlds

    Needle Engine supports the sessiongranted state. This allows users to seamlessly traverse between WebXR applications without leaving an immersive session โ€“ they stay in VR or AR.

    Currently, this is only supported on Oculus Quest 1, 2 and 3 in the Oculus Browser. On other platforms, users will be kicked out of their current immersive session and have to enter VR again on the new page.
    Requires enabling a browser flag: chrome://flags/#webxr-navigation-permission

    • Click on objects to open links
      Add the OpenURL component that makes it very easy to build connected worlds.

    Scripting

    ',19)),t("p",null,[e[25]||(e[25]=s("Read more about scripting for XR at the ")),i(n,{to:"/scripting.html#xr-event-methods"},{default:r(()=>e[24]||(e[24]=[s("scripting XR documentation")])),_:1})]),e[37]||(e[37]=a(`

    Avatars

    While we don't currently provide an out-of-the-box integration external avatar systems, you can create application-specific avatars or custom systems.

    • Create a custom Avatar
      • Create an empty GameObject as avatar root
      • Add an object named Head and add a XRFlag that's set to Third Person
      • Add objects named HandLeft and HandRight
      • Add your graphics below these objects.

    Experimental Avatar Components

    There's a number of experimental components to build more expressive Avatars. At this point we recommended duplicating them to make your own variants, since they might be changed or removed at a later point.

    20220817-230858-87dG-Unity_PLjQ
    Example Avatar Rig with basic neck model and limb constraints

    • Random Player Colors
      As an example for avatar customization, you can add a PlayerColor component to your renderers.
      This randomized color is synchronized between players.

    • Eye Rotation
      AvatarEyeLook_Rotation rotates GameObjects (eyes) to follow other avatars and a random target. This component is synchronized between players.

    • Eye Blinking
      AvatarBlink_Simple randomly hides GameObjects (eyes) every few seconds, emulating a blink.

      image
      Example Avatar Prefab hierarchy

    • Offset Constraint
      OffsetConstraint allows to shift an object in relation to another one in Avatar space. This allows, for example, to have a Body follow the Head but keep rotation levelled. It also allows to construct simple neck models.

    • Limb Constraint
      BasicIKConstraint is a very minimalistic constraint that takes two transforms and a hint. This is useful to construct simple arm or leg chains. As rotation is currently not properly implemented, arms and legs may need to be rotationally symmetric to "look right". It's called "Basic" for a reason!

    HTML Content Overlays in AR

    If you want to display different html content whether the client is using a regular browser or using AR or VR, you can just use a set of html classes.
    This is controlled via HTML element classes. For example, to make content appear on desktop and in AR add a <div class="desktop ar"> ... </div> inside the <needle-engine> tag:

    <needle-engine>
    +    <div class="desktop ar" style="pointer-events:none;">
    +        <div class="positioning-container">
    +          <p>your content for AR and desktop goes here</p>
    +          <p class="only-in-ar">This will only be visible in AR</p>
    +        <div>
    +    </div>
    +</needle-engine>

    Content Overlays are implemented using the optional dom-overlay feature which is usually supported on screen-based AR devices (phones, tablets).

    Use the .ar-session-active class to show/hide specific content while in AR. The :xr-overlay pseudo class shouldn't be used at this point because using it breaks Mozilla's WebXR Viewer.

    .only-in-ar {
    +  display: none;
    +}
    +
    +.ar-session-active .only-in-ar {
    +  display:initial;
    +}

    It's worth noting that the overlay element will be always displayed fullscreen while in XR, independent of styling that has been applied. If you want to align items differently, you should make a container inside the class="ar" element.

    `,14)),i(l,{src:"https://engine.needle.tools/samples-uploads/ar-overlay/"}),e[38]||(e[38]=a('

    Image Tracking

    Needle Engine supports WebXR ImageTracking (Live Demo)
    Note: While WebXR ImageTracking is still in "draft" phase (Marker Tracking Explainer)
    you need to follow these steps to enable WebXR ImageTracking on Android devices:

    • Enable WebXR Incubations in chrome
    • Add the WebXRImageTracking component
    ',3)),t("p",null,[e[27]||(e[27]=s("You can find additional documentation in the ")),i(n,{to:"/everywhere-actions.html#image-tracking"},{default:r(()=>e[26]||(e[26]=[s("Everywhere Actions")])),_:1}),e[28]||(e[28]=s(" section"))]),e[39]||(e[39]=a('

    Without that spec, one can still request camera image access and run custom algorithms to determine device pose.
    Libraries to add image tracking:

    Augmented Reality and WebXR on iOS

    Augmented Reality experiences on iOS are somewhat limited, due to Apple currently not supporting WebXR on iOS devices.

    ',4)),t("p",null,[e[31]||(e[31]=s("Needle Engine's ")),i(n,{to:"/everywhere-actions.html"},{default:r(()=>e[29]||(e[29]=[s("Everywhere Actions")])),_:1}),e[32]||(e[32]=s(" are designed to fill that gap, bringing automatic interactive capabilities to iOS devices for scenes composed of specific components. They support a subset of the functionality that's available in WebXR, for example spatial audio, image tracking, animations, and more. See ")),i(n,{to:"/everywhere-actions.html"},{default:r(()=>e[30]||(e[30]=[s("the docs")])),_:1}),e[33]||(e[33]=s(" for more information."))]),e[40]||(e[40]=t("h3",{id:"musical-instrument-webxr-and-quicklook-support",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#musical-instrument-webxr-and-quicklook-support"},[t("span",null,"Musical Instrument โ€“ WebXR and QuickLook support")])],-1)),e[41]||(e[41]=t("p",null,"Here's an example for a musical instrument that uses Everywhere Actions and thus works in browsers and in AR on iOS devices. It uses spatial audio, animation, and tap interactions.",-1)),i(l,{src:"https://engine.needle.tools/samples-uploads/musical-instrument"}),e[42]||(e[42]=a('

    Everywhere Actions and other options for iOS AR

    There's also other options for guiding iOS users to even more capable interactive AR experiences:

    1. Exporting content on-the-fly as USDZ files.
      These files can be displayed on iOS devices in AR. When exported from scenes with Everywhere Actions the interactivity is the same, more than sufficient for product configurators, narrative experiences and similar. An example is Castle Builder where creations (not the live session) can be viewed in AR.

    Encryption in Space uses this approach. Players can collaboratively place text into the scene on their screens and then view the results in AR on iOS. On Android, they can also interact right in WebXR.
    โ€” #madewithneedle by Katja Rempel ๐Ÿ’š

    1. Guiding users towards WebXR-compatible browsers on iOS. Depending on your target audience, you can guide users on iOS towards for example Mozilla's WebXR Viewer to experience AR on iOS.

    2. Using camera access and custom algorithms on iOS devices.
      One can request camera image access and run custom algorithms to determine device pose.
      While we currently don't provide built-in components for this, here's a few references to libraries and frameworks that we want to try in the future:

    References

    WebXR Device API
    caniuse: WebXR
    Apple's Preliminary USD Behaviours

    ',7))])}const m=d(c,[["render",u],["__file","xr.html.vue"]]),b=JSON.parse(`{"path":"/xr.html","title":"VR & AR (WebXR)","lang":"en-US","frontmatter":{"title":"VR & AR (WebXR)","head":[["meta",{"name":"og:image","content":"https://engine.needle.tools/docs/.preview/vr & ar.png"}],["meta",{"name":"og:description","content":"---\\nTheoretically all WebXR-capable devices and browsers should be supported. That being said, we've tested the following configurations:"}]],"description":"---\\nTheoretically all WebXR-capable devices and browsers should be supported. That being said, we've tested the following configurations:"},"headers":[{"level":2,"title":"Supported Devices","slug":"supported-devices","link":"#supported-devices","children":[]},{"level":2,"title":"Examples","slug":"examples","link":"#examples","children":[]},{"level":2,"title":"Adding VR and AR capabilities to a scene","slug":"adding-vr-and-ar-capabilities-to-a-scene","link":"#adding-vr-and-ar-capabilities-to-a-scene","children":[{"level":3,"title":"Basic capabilities","slug":"basic-capabilities","link":"#basic-capabilities","children":[]},{"level":3,"title":"Multiplayer","slug":"multiplayer","link":"#multiplayer","children":[]},{"level":3,"title":"Special AR Components","slug":"special-ar-components","link":"#special-ar-components","children":[]},{"level":3,"title":"Controlling object display for XR","slug":"controlling-object-display-for-xr","link":"#controlling-object-display-for-xr","children":[]},{"level":3,"title":"Travelling between VR worlds","slug":"travelling-between-vr-worlds","link":"#travelling-between-vr-worlds","children":[]}]},{"level":2,"title":"Scripting","slug":"scripting","link":"#scripting","children":[]},{"level":2,"title":"Avatars","slug":"avatars","link":"#avatars","children":[{"level":3,"title":"Experimental Avatar Components","slug":"experimental-avatar-components","link":"#experimental-avatar-components","children":[]}]},{"level":2,"title":"HTML Content Overlays in AR","slug":"html-content-overlays-in-ar","link":"#html-content-overlays-in-ar","children":[]},{"level":2,"title":"Image Tracking","slug":"image-tracking","link":"#image-tracking","children":[]},{"level":2,"title":"Augmented Reality and WebXR on iOS","slug":"augmented-reality-and-webxr-on-ios","link":"#augmented-reality-and-webxr-on-ios","children":[{"level":3,"title":"Musical Instrument โ€“ WebXR and QuickLook support","slug":"musical-instrument-webxr-and-quicklook-support","link":"#musical-instrument-webxr-and-quicklook-support","children":[]},{"level":3,"title":"Everywhere Actions and other options for iOS AR","slug":"everywhere-actions-and-other-options-for-ios-ar","link":"#everywhere-actions-and-other-options-for-ios-ar","children":[]}]},{"level":2,"title":"References","slug":"references","link":"#references","children":[]}],"git":{"updatedTime":1726086775000},"filePathRelative":"xr.md"}`);export{m as comp,b as data}; diff --git a/backlog-mermaid.html b/backlog-mermaid.html new file mode 100644 index 000000000..8b6c8e487 --- /dev/null +++ b/backlog-mermaid.html @@ -0,0 +1,56 @@ + + + + + + + + + Needle Engine Documentation + + + + + +
    + + + diff --git a/backlog.html b/backlog.html new file mode 100644 index 000000000..48214a013 --- /dev/null +++ b/backlog.html @@ -0,0 +1,43 @@ + + + + + + + + + Documentation Backlog | Needle Engine Documentation + + + + + +
    + + + diff --git a/blender/animation.mp4 b/blender/animation.mp4 new file mode 100644 index 000000000..bed4e28ab Binary files /dev/null and b/blender/animation.mp4 differ diff --git a/blender/animatorcontroller-assigning.webp b/blender/animatorcontroller-assigning.webp new file mode 100644 index 000000000..83fcc1662 Binary files /dev/null and b/blender/animatorcontroller-assigning.webp differ diff --git a/blender/animatorcontroller-create.mp4 b/blender/animatorcontroller-create.mp4 new file mode 100644 index 000000000..02f0e9ecf Binary files /dev/null and b/blender/animatorcontroller-create.mp4 differ diff --git a/blender/animatorcontroller-open.webp b/blender/animatorcontroller-open.webp new file mode 100644 index 000000000..72789a534 Binary files /dev/null and b/blender/animatorcontroller-open.webp differ diff --git a/blender/animatorcontroller-overview.webp b/blender/animatorcontroller-overview.webp new file mode 100644 index 000000000..ce4e9653d Binary files /dev/null and b/blender/animatorcontroller-overview.webp differ diff --git a/blender/animatorcontroller-web.mp4 b/blender/animatorcontroller-web.mp4 new file mode 100644 index 000000000..f16d0d4e0 Binary files /dev/null and b/blender/animatorcontroller-web.mp4 differ diff --git a/blender/bugreporter.webp b/blender/bugreporter.webp new file mode 100644 index 000000000..74631d65d Binary files /dev/null and b/blender/bugreporter.webp differ diff --git a/blender/components-panel-select.webp b/blender/components-panel-select.webp new file mode 100644 index 000000000..acc481369 Binary files /dev/null and b/blender/components-panel-select.webp differ diff --git a/blender/components-panel.webp b/blender/components-panel.webp new file mode 100644 index 000000000..ae799f141 Binary files /dev/null and b/blender/components-panel.webp differ diff --git a/blender/custom_hdri.mp4 b/blender/custom_hdri.mp4 new file mode 100644 index 000000000..9b516dd25 Binary files /dev/null and b/blender/custom_hdri.mp4 differ diff --git a/blender/deploy_to_glitch.webp b/blender/deploy_to_glitch.webp new file mode 100644 index 000000000..d5985a13d Binary files /dev/null and b/blender/deploy_to_glitch.webp differ diff --git a/blender/dont-export.webp b/blender/dont-export.webp new file mode 100644 index 000000000..8fd0cf01c Binary files /dev/null and b/blender/dont-export.webp differ diff --git a/blender/environment-camera.webp b/blender/environment-camera.webp new file mode 100644 index 000000000..71069c509 Binary files /dev/null and b/blender/environment-camera.webp differ diff --git a/blender/environment-light.mp4 b/blender/environment-light.mp4 new file mode 100644 index 000000000..f50b71977 Binary files /dev/null and b/blender/environment-light.mp4 differ diff --git a/blender/environment.mp4 b/blender/environment.mp4 new file mode 100644 index 000000000..f9db730e8 Binary files /dev/null and b/blender/environment.mp4 differ diff --git a/blender/environment.webp b/blender/environment.webp new file mode 100644 index 000000000..0b2a8d00d Binary files /dev/null and b/blender/environment.webp differ diff --git a/blender/index.html b/blender/index.html new file mode 100644 index 000000000..17433c1a7 --- /dev/null +++ b/blender/index.html @@ -0,0 +1,77 @@ + + + + + + + + + Needle Engine for Blender | Needle Engine Documentation + + + + + +
    + + + diff --git a/blender/lightmapping-object.webp b/blender/lightmapping-object.webp new file mode 100644 index 000000000..822c765c4 Binary files /dev/null and b/blender/lightmapping-object.webp differ diff --git a/blender/lightmapping-panel.webp b/blender/lightmapping-panel.webp new file mode 100644 index 000000000..cc265138c Binary files /dev/null and b/blender/lightmapping-panel.webp differ diff --git a/blender/lightmapping-scene-panel.webp b/blender/lightmapping-scene-panel.webp new file mode 100644 index 000000000..a6f145989 Binary files /dev/null and b/blender/lightmapping-scene-panel.webp differ diff --git a/blender/lightmapping.mp4 b/blender/lightmapping.mp4 new file mode 100644 index 000000000..a25642d63 Binary files /dev/null and b/blender/lightmapping.mp4 differ diff --git a/blender/logo.png b/blender/logo.png new file mode 100644 index 000000000..8f04e2756 Binary files /dev/null and b/blender/logo.png differ diff --git a/blender/object-panels.webp b/blender/object-panels.webp new file mode 100644 index 000000000..63a533f26 Binary files /dev/null and b/blender/object-panels.webp differ diff --git a/blender/project-panel-2.webp b/blender/project-panel-2.webp new file mode 100644 index 000000000..8a8745c48 Binary files /dev/null and b/blender/project-panel-2.webp differ diff --git a/blender/project-panel-3.webp b/blender/project-panel-3.webp new file mode 100644 index 000000000..e1fe1c80f Binary files /dev/null and b/blender/project-panel-3.webp differ diff --git a/blender/project-panel.webp b/blender/project-panel.webp new file mode 100644 index 000000000..768f411d0 Binary files /dev/null and b/blender/project-panel.webp differ diff --git a/blender/remove-component.webp b/blender/remove-component.webp new file mode 100644 index 000000000..58191b706 Binary files /dev/null and b/blender/remove-component.webp differ diff --git a/blender/settings-color-management.webp b/blender/settings-color-management.webp new file mode 100644 index 000000000..3cb381249 Binary files /dev/null and b/blender/settings-color-management.webp differ diff --git a/blender/settings.webp b/blender/settings.webp new file mode 100644 index 000000000..3e7166b68 Binary files /dev/null and b/blender/settings.webp differ diff --git a/blender/texture-compression.webp b/blender/texture-compression.webp new file mode 100644 index 000000000..7a08a6ed6 Binary files /dev/null and b/blender/texture-compression.webp differ diff --git a/blender/timeline.webp b/blender/timeline.webp new file mode 100644 index 000000000..1362d3808 Binary files /dev/null and b/blender/timeline.webp differ diff --git a/blender/timeline_setup.webp b/blender/timeline_setup.webp new file mode 100644 index 000000000..6771cd7e8 Binary files /dev/null and b/blender/timeline_setup.webp differ diff --git a/blender/updates.webp b/blender/updates.webp new file mode 100644 index 000000000..8dc20e608 Binary files /dev/null and b/blender/updates.webp differ diff --git a/castle.png b/castle.png new file mode 100644 index 000000000..8e0f89573 Binary files /dev/null and b/castle.png differ diff --git a/code-samples/basic-component.ts b/code-samples/basic-component.ts new file mode 100644 index 000000000..ff1cb9931 --- /dev/null +++ b/code-samples/basic-component.ts @@ -0,0 +1,16 @@ +import { Behaviour, serializable } from "@needle-tools/engine" +import { Object3D } from "three" + +export class MyComponent extends Behaviour { + + @serializable(Object3D) + myObjectReference?: Object3D; + + start() { + console.log("Hello world", this); + } + + update() { + this.gameObject.rotateY(this.context.time.deltaTime); + } +} \ No newline at end of file diff --git a/code-samples/basic-html.html b/code-samples/basic-html.html new file mode 100644 index 000000000..ff5096f90 --- /dev/null +++ b/code-samples/basic-html.html @@ -0,0 +1,52 @@ + + + + + + + + Made with Needle + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/code-samples/basic-webcomponent.html b/code-samples/basic-webcomponent.html new file mode 100644 index 000000000..b6f34df92 --- /dev/null +++ b/code-samples/basic-webcomponent.html @@ -0,0 +1,18 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/code-samples/component-2d-audio.ts b/code-samples/component-2d-audio.ts new file mode 100644 index 000000000..bea8ddd81 --- /dev/null +++ b/code-samples/component-2d-audio.ts @@ -0,0 +1,22 @@ +import { AudioSource, Behaviour, serializable } from "@needle-tools/engine"; + +// declaring AudioClip type is for codegen to produce the correct input field (for e.g. Unity or Blender) +declare type AudioClip = string; + +export class My2DAudio extends Behaviour { + + // The clip contains a string pointing to the audio file - by default it's relative to the GLB that contains the component + // by adding the URL decorator the clip string will be resolved relative to your project root and can be loaded + @serializable(URL) + clip?: AudioClip; + + awake() { + // creating a new audio element and playing it + const audioElement = new Audio(this.clip); + audioElement.loop = true; + // on the web we have to wait for the user to interact with the page before we can play audio + AudioSource.registerWaitForAllowAudio(() => { + audioElement.play(); + }) + } +} \ No newline at end of file diff --git a/code-samples/component-animation-onclick.ts b/code-samples/component-animation-onclick.ts new file mode 100644 index 000000000..365d684fe --- /dev/null +++ b/code-samples/component-animation-onclick.ts @@ -0,0 +1,20 @@ +import { Behaviour, serializable, Animation, IPointerClickHandler, PointerEventData } from "@needle-tools/engine"; + +export class PlayAnimationOnClick extends Behaviour implements IPointerClickHandler { + + @serializable(Animation) + animation?: Animation; + + awake() { + if (this.animation) { + this.animation.playAutomatically = false; + this.animation.loop = false; + } + } + + onPointerClick(_args: PointerEventData) { + if (this.animation) { + this.animation.play(); + } + } +} \ No newline at end of file diff --git a/code-samples/component-animationclip.ts b/code-samples/component-animationclip.ts new file mode 100644 index 000000000..54be3cb12 --- /dev/null +++ b/code-samples/component-animationclip.ts @@ -0,0 +1,12 @@ +import { Behaviour, serializable } from "@needle-tools/engine"; +import { AnimationClip } from "three" + +export class ExportAnimationClip extends Behaviour { + + @serializable(AnimationClip) + animation?: AnimationClip; + + awake() { + console.log("My referenced animation clip", this.animation); + } +} \ No newline at end of file diff --git a/code-samples/component-click-networking.ts b/code-samples/component-click-networking.ts new file mode 100644 index 000000000..5ca54dd62 --- /dev/null +++ b/code-samples/component-click-networking.ts @@ -0,0 +1,27 @@ +import { Behaviour, EventList, IPointerClickHandler, PointerEventData, serializable } from "@needle-tools/engine"; + +export class SyncedClick extends Behaviour implements IPointerClickHandler { + + @serializable(EventList) + onClick!: EventList; + + onPointerClick(_args: PointerEventData) { + console.log("SEND CLICK"); + this.context.connection.send("clicked/" + this.guid); + this.onClick?.invoke(); + } + + onEnable(): void { + this.context.connection.beginListen("clicked/" + this.guid, this.onRemoteClick); + } + onDisable(): void { + this.context.connection.stopListen("clicked/" + this.guid, this.onRemoteClick); + } + + + onRemoteClick = () => { + console.log("RECEIVED CLICK"); + this.onClick?.invoke(); + } + +} \ No newline at end of file diff --git a/code-samples/component-click.ts b/code-samples/component-click.ts new file mode 100644 index 000000000..d90e185cd --- /dev/null +++ b/code-samples/component-click.ts @@ -0,0 +1,9 @@ +import { Behaviour, IPointerClickHandler, PointerEventData, showBalloonMessage } from "@needle-tools/engine"; + +export class ClickExample extends Behaviour implements IPointerClickHandler { + + // Make sure to have an ObjectRaycaster component in the parent hierarchy + onPointerClick(_args: PointerEventData) { + showBalloonMessage("Clicked " + this.name); + } +} diff --git a/code-samples/component-customevent.ts b/code-samples/component-customevent.ts new file mode 100644 index 000000000..b6bb933bf --- /dev/null +++ b/code-samples/component-customevent.ts @@ -0,0 +1,42 @@ +import { Behaviour, serializable, EventList } from "@needle-tools/engine"; +import { Object3D } from "three"; + +/* +Make sure to have a c# file in your project with the following content: + +using UnityEngine; +using UnityEngine.Events; + +[System.Serializable] +public class MyCustomUnityEvent : UnityEvent +{ +} + +Unity documentation about custom events: +https://docs.unity3d.com/ScriptReference/Events.UnityEvent_2.html + +*/ + +// Documentation โ†’ https://docs.needle.tools/scripting + +export class CustomEventCaller extends Behaviour { + + // The next line is not just a comment, it defines + // a specific type for the component generator to use. + + //@type MyCustomUnityEvent + @serializable(EventList) + myEvent!: EventList; + + // just for testing - could be when a button is clicked, etc. + start() { + this.myEvent.invoke("Hello"); + } +} + +export class CustomEventReceiver extends Behaviour { + + logStringAndObject(str: string) { + console.log("From Event: ", str); + } +} \ No newline at end of file diff --git a/code-samples/component-customshaderproperty.ts b/code-samples/component-customshaderproperty.ts new file mode 100644 index 000000000..949e304d8 --- /dev/null +++ b/code-samples/component-customshaderproperty.ts @@ -0,0 +1,20 @@ +import { Behaviour, serializable } from "@needle-tools/engine"; +import { Material } from "three"; + +declare type MyCustomShaderMaterial = Material & { + _Speed: number; +}; + +export class IncreaseShaderSpeedOverTime extends Behaviour { + + //@type UnityEngine.Material + @serializable(Material) + myMaterial?: MyCustomShaderMaterial; + + update() { + if (this.myMaterial) { + this.myMaterial._Speed *= 1 + this.context.time.deltaTime; + if(this.myMaterial._Speed > 1) this.myMaterial._Speed = .0005; + } + } +} \ No newline at end of file diff --git a/code-samples/component-everywhere-action-hideonstart.ts b/code-samples/component-everywhere-action-hideonstart.ts new file mode 100644 index 000000000..9a90a2076 --- /dev/null +++ b/code-samples/component-everywhere-action-hideonstart.ts @@ -0,0 +1,24 @@ +import { Behaviour, UsdzBehaviour, BehaviorModel, TriggerBuilder, ActionBuilder, BehaviorExtension, USDObject, USDZExporterContext } from "@needle-tools/engine"; + +export class HideOnStart extends Behaviour implements UsdzBehaviour { + + start() { + this.gameObject.visible = false; + } + + createBehaviours(ext: BehaviorExtension, model: USDObject, _context: USDZExporterContext) { + if (model.uuid === this.gameObject.uuid) + ext.addBehavior(new BehaviorModel("HideOnStart_" + this.gameObject.name, + TriggerBuilder.sceneStartTrigger(), + ActionBuilder.fadeAction(model, 0, false) + )); + } + + beforeCreateDocument() { + this.gameObject.visible = true; + } + + afterCreateDocument() { + this.gameObject.visible = false; + } +} \ No newline at end of file diff --git a/code-samples/component-filereference.ts b/code-samples/component-filereference.ts new file mode 100644 index 000000000..387ba54eb --- /dev/null +++ b/code-samples/component-filereference.ts @@ -0,0 +1,20 @@ +import { Behaviour, FileReference, ImageReference, serializable } from "@needle-tools/engine"; + +export class FileReferenceExample extends Behaviour { + + // A FileReference can be used to load and assign arbitrary data in the editor. You can use it to load images, audio, text files... FileReference types will not be saved inside as part of the GLB (the GLB will only contain a relative URL to the file) + @serializable(FileReference) + myFile?: FileReference; + // Tip: if you want to export and load an image (that is not part of your GLB) if you intent to add it to your HTML content for example you can use the ImageReference type instead of FileReference. It will be loaded as an image and you can use it as a source for an tag. + + async start() { + console.log("This is my file: ", this.myFile); + // load the file + const data = await this.myFile?.loadRaw(); + if (!data) { + console.error("Failed loading my file..."); + return; + } + console.log("Loaded my file. These are the bytes:", await data.arrayBuffer()); + } +} \ No newline at end of file diff --git a/code-samples/component-location.ts b/code-samples/component-location.ts new file mode 100644 index 000000000..bb95f392b --- /dev/null +++ b/code-samples/component-location.ts @@ -0,0 +1,11 @@ +import { Behaviour, showBalloonMessage } from "@needle-tools/engine"; + +export class WhereAmI extends Behaviour { + start() { + navigator.geolocation.getCurrentPosition((position) => { + console.log("Navigator response:", position); + const latlong = position.coords.latitude + ", " + position.coords.longitude; + showBalloonMessage("You are at\nLatLong " + latlong); + }); + } +} \ No newline at end of file diff --git a/code-samples/component-nested-serialization-cs.cs b/code-samples/component-nested-serialization-cs.cs new file mode 100644 index 000000000..445a11183 --- /dev/null +++ b/code-samples/component-nested-serialization-cs.cs @@ -0,0 +1,17 @@ +using System; + +[Serializable] +public class CustomSubData +{ + public string subString; + public float subNumber; +} + +[Serializable] +public class CustomData +{ + public string myStringField; + public float myNumberField; + public bool myBooleanField; + public CustomSubData subData; +} \ No newline at end of file diff --git a/code-samples/component-nested-serialization.ts b/code-samples/component-nested-serialization.ts new file mode 100644 index 000000000..2a3a4473c --- /dev/null +++ b/code-samples/component-nested-serialization.ts @@ -0,0 +1,40 @@ +import { Behaviour, serializable } from "@needle-tools/engine"; + +// Documentation โ†’ https://docs.needle.tools/scripting + +class CustomSubData { + @serializable() + subString: string = ""; + + @serializable() + subNumber: number = 0; +} + +class CustomData { + @serializable() + myStringField: string = ""; + + @serializable() + myNumberField: number = 0; + + @serializable() + myBooleanField: boolean = false; + + @serializable(CustomSubData) + subData: CustomSubData | undefined = undefined; + + someMethod() { + console.log("My string is " + this.myStringField, "my sub data", this.subData) + } +} + +export class SerializedDataSample extends Behaviour { + + @serializable(CustomData) + myData: CustomData | undefined; + + onEnable() { + console.log(this.myData); + this.myData?.someMethod(); + } +} \ No newline at end of file diff --git a/code-samples/component-object-reference.ts b/code-samples/component-object-reference.ts new file mode 100644 index 000000000..f3a94e49c --- /dev/null +++ b/code-samples/component-object-reference.ts @@ -0,0 +1,13 @@ +import { Behaviour, serializable } from "@needle-tools/engine"; +import { Object3D } from "three" + +export class MyClass extends Behaviour { + // this will be a "Transform" field in Unity + @serializable(Object3D) + myObjectReference: Object3D | null = null; + + // this will be a "Transform" array field in Unity + // Note that the @serializable decorator contains the array content type! (Object3D and not Object3D[]) + @serializable(Object3D) + myObjectReferenceList: Object3D[] | null = null; +} \ No newline at end of file diff --git a/code-samples/component-prefab.ts b/code-samples/component-prefab.ts new file mode 100644 index 000000000..73f5551ee --- /dev/null +++ b/code-samples/component-prefab.ts @@ -0,0 +1,20 @@ +import { Behaviour, serializable, AssetReference } from "@needle-tools/engine"; + +export class MyClass extends Behaviour { + + // if you export a prefab or scene as a reference from Unity you'll get a path to that asset + // which you can de-serialize to AssetReference for convenient loading + @serializable(AssetReference) + myPrefab?: AssetReference; + + async start() { + // directly instantiate + const myInstance = await this.myPrefab?.instantiate(); + + // you can also just load and instantiate later + // const myInstance = await this.myPrefab.loadAssetAsync(); + // this.gameObject.add(myInstance) + // this is useful if you know that you want to load this asset only once because it will not create a copy + // since ``instantiate()`` does create a copy of the asset after loading it + } +} \ No newline at end of file diff --git a/code-samples/component-scene.ts b/code-samples/component-scene.ts new file mode 100644 index 000000000..38fdfa048 --- /dev/null +++ b/code-samples/component-scene.ts @@ -0,0 +1,34 @@ +import { Behaviour, serializable, AssetReference } from "@needle-tools/engine"; + +export class LoadingScenes extends Behaviour { + // tell the component compiler that we want to reference an array of SceneAssets + // @type UnityEditor.SceneAsset[] + @serializable(AssetReference) + myScenes?: AssetReference[]; + + async awake() { + if (!this.myScenes) { + return; + } + for (const scene of this.myScenes) { + // check if it is assigned in unity + if(!scene) continue; + // load the scene once + const myScene = await scene.loadAssetAsync(); + // add it to the threejs scene + this.gameObject.add(myScene); + + // of course you can always just load one at a time + // and remove it from the scene when you want + // myScene.removeFromParent(); + // this is the same as scene.asset.removeFromParent() + } + } + + onDestroy(): void { + if (!this.myScenes) return; + for (const scene of this.myScenes) { + scene?.unload(); + } + } +} \ No newline at end of file diff --git a/code-samples/component-time.ts b/code-samples/component-time.ts new file mode 100644 index 000000000..9c7e8431a --- /dev/null +++ b/code-samples/component-time.ts @@ -0,0 +1,21 @@ +import { Behaviour, Text, serializable, WaitForSeconds } from "@needle-tools/engine"; + +export class DisplayTime extends Behaviour { + + @serializable(Text) + text?: Text; + + onEnable(): void { + this.startCoroutine(this.updateTime()) + } + + private *updateTime() { + while (true) { + if (this.text) { + this.text.text = new Date().toLocaleTimeString(); + console.log(this.text.text) + } + yield WaitForSeconds(1) + } + }; +} \ No newline at end of file diff --git a/code-samples/component-unityevent.ts b/code-samples/component-unityevent.ts new file mode 100644 index 000000000..3f326a790 --- /dev/null +++ b/code-samples/component-unityevent.ts @@ -0,0 +1,11 @@ +import { Behaviour, serializable, EventList } from "@needle-tools/engine" + +export class MyComponent extends Behaviour { + + @serializable(EventList) + myEvent? : EventList; + + start() { + this.myEvent?.invoke(); + } +} \ No newline at end of file diff --git a/code-samples/custom-particle-system-behaviour.ts b/code-samples/custom-particle-system-behaviour.ts new file mode 100644 index 000000000..f12b58eb0 --- /dev/null +++ b/code-samples/custom-particle-system-behaviour.ts @@ -0,0 +1,17 @@ +import { Behaviour, ParticleSystem } from "@needle-tools/engine"; +import { ParticleSystemBaseBehaviour, QParticle } from "@needle-tools/engine"; + +// Derive your custom behaviour from the ParticleSystemBaseBehaviour class (or use QParticleBehaviour) +class MyParticlesBehaviour extends ParticleSystemBaseBehaviour { + + // callback invoked per particle + update(particle: QParticle): void { + particle.position.y += 5 * this.context.time.deltaTime; + } +} +export class TestCustomParticleSystemBehaviour extends Behaviour { + start() { + // add your custom behaviour to the particle system + this.gameObject.getComponent(ParticleSystem)!.addBehaviour(new MyParticlesBehaviour()) + } +} diff --git a/code-samples/custom-post-effect.ts b/code-samples/custom-post-effect.ts new file mode 100644 index 000000000..3d6c6cfc5 --- /dev/null +++ b/code-samples/custom-post-effect.ts @@ -0,0 +1,44 @@ +import { EffectProviderResult, PostProcessingEffect, registerCustomEffectType, serializable } from "@needle-tools/engine"; +import { OutlineEffect } from "postprocessing"; +import { Object3D } from "three"; + +export class OutlinePostEffect extends PostProcessingEffect { + + // the outline effect takes a list of objects to outline + @serializable(Object3D) + selection!: Object3D[]; + + // this is just an example method that you could call to update the outline effect selection + updateSelection() { + if (this._outlineEffect) { + this._outlineEffect.selection.clear(); + for (const obj of this.selection) { + this._outlineEffect.selection.add(obj); + } + } + } + + + // a unique name is required for custom effects + get typeName(): string { + return "Outline"; + } + + private _outlineEffect: void | undefined | OutlineEffect; + + // method that creates the effect once + onCreateEffect(): EffectProviderResult | undefined { + + const outlineEffect = new OutlineEffect(this.context.scene, this.context.mainCamera!); + this._outlineEffect = outlineEffect; + outlineEffect.edgeStrength = 10; + outlineEffect.visibleEdgeColor.set(0xff0000); + for (const obj of this.selection) { + outlineEffect.selection.add(obj); + } + + return outlineEffect; + } +} +// You need to register your effect type with the engine +registerCustomEffectType("Outline", OutlinePostEffect); \ No newline at end of file diff --git a/community/contributions.html b/community/contributions.html new file mode 100644 index 000000000..2e1728985 --- /dev/null +++ b/community/contributions.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Gosh! You found a ๐ŸŒต glitch
    Take me home
    + + + diff --git a/community/contributions/ericcraft-mh.html b/community/contributions/ericcraft-mh.html new file mode 100644 index 000000000..65486d752 --- /dev/null +++ b/community/contributions/ericcraft-mh.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Gosh! You found a ๐ŸŒต glitch
    Take me home
    + + + diff --git a/community/contributions/ericcraft-mh/quicklook-vertical-image-tracker.html b/community/contributions/ericcraft-mh/quicklook-vertical-image-tracker.html new file mode 100644 index 000000000..0f63a23b3 --- /dev/null +++ b/community/contributions/ericcraft-mh/quicklook-vertical-image-tracker.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Gosh! You found a ๐ŸŒต glitch
    Take me home
    + + + diff --git a/community/contributions/kipash.html b/community/contributions/kipash.html new file mode 100644 index 000000000..fa73fcee2 --- /dev/null +++ b/community/contributions/kipash.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Oh no โ€” this page does not exist!
    Take me home
    + + + diff --git a/community/contributions/kipash/calculate-pointer-world-position.html b/community/contributions/kipash/calculate-pointer-world-position.html new file mode 100644 index 000000000..ad57ce209 --- /dev/null +++ b/community/contributions/kipash/calculate-pointer-world-position.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Oh no โ€” this page does not exist!
    Take me home
    + + + diff --git a/community/contributions/krisrok.html b/community/contributions/krisrok.html new file mode 100644 index 000000000..ba7166e9e --- /dev/null +++ b/community/contributions/krisrok.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Gosh! You found a ๐ŸŒต glitch
    Take me home
    + + + diff --git a/community/contributions/krisrok/always-open-in-specific-browser.html b/community/contributions/krisrok/always-open-in-specific-browser.html new file mode 100644 index 000000000..5724c99d3 --- /dev/null +++ b/community/contributions/krisrok/always-open-in-specific-browser.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Oh no โ€” this page does not exist!
    Take me home
    + + + diff --git a/community/contributions/llllkatjallll.html b/community/contributions/llllkatjallll.html new file mode 100644 index 000000000..39d476b9d --- /dev/null +++ b/community/contributions/llllkatjallll.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Gosh! You found a ๐ŸŒต glitch
    Take me home
    + + + diff --git a/community/contributions/llllkatjallll/custom-vr-button-that-appears-only-on-headsets-and-not-on-mobile-phones.html b/community/contributions/llllkatjallll/custom-vr-button-that-appears-only-on-headsets-and-not-on-mobile-phones.html new file mode 100644 index 000000000..319abdbad --- /dev/null +++ b/community/contributions/llllkatjallll/custom-vr-button-that-appears-only-on-headsets-and-not-on-mobile-phones.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Oh no โ€” this page does not exist!
    Take me home
    + + + diff --git a/community/contributions/llllkatjallll/set-fallback-material-for-usdz-exporter.html b/community/contributions/llllkatjallll/set-fallback-material-for-usdz-exporter.html new file mode 100644 index 000000000..4fc0793ff --- /dev/null +++ b/community/contributions/llllkatjallll/set-fallback-material-for-usdz-exporter.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Oh no โ€” this page does not exist!
    Take me home
    + + + diff --git a/community/contributions/marwie.html b/community/contributions/marwie.html new file mode 100644 index 000000000..53be7594f --- /dev/null +++ b/community/contributions/marwie.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Gosh! You found a ๐ŸŒต glitch
    Take me home
    + + + diff --git a/community/contributions/marwie/camera-video-background.html b/community/contributions/marwie/camera-video-background.html new file mode 100644 index 000000000..7fe67dc29 --- /dev/null +++ b/community/contributions/marwie/camera-video-background.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Gosh! You found a ๐ŸŒต glitch
    Take me home
    + + + diff --git a/community/contributions/marwie/code-contribution-example.html b/community/contributions/marwie/code-contribution-example.html new file mode 100644 index 000000000..c85eb1f00 --- /dev/null +++ b/community/contributions/marwie/code-contribution-example.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Oh no โ€” this page does not exist!
    Take me home
    + + + diff --git a/community/contributions/marwie/control-a-timeline-by-scroll.html b/community/contributions/marwie/control-a-timeline-by-scroll.html new file mode 100644 index 000000000..8db5e6d60 --- /dev/null +++ b/community/contributions/marwie/control-a-timeline-by-scroll.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Gosh! You found a ๐ŸŒต glitch
    Take me home
    + + + diff --git a/community/contributions/marwie/everywhere-action-emphasize-on-click.html b/community/contributions/marwie/everywhere-action-emphasize-on-click.html new file mode 100644 index 000000000..c26a23a75 --- /dev/null +++ b/community/contributions/marwie/everywhere-action-emphasize-on-click.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Oh no โ€” this page does not exist!
    Take me home
    + + + diff --git a/community/contributions/marwie/usdz-hide-object-on-start.html b/community/contributions/marwie/usdz-hide-object-on-start.html new file mode 100644 index 000000000..6283c007e --- /dev/null +++ b/community/contributions/marwie/usdz-hide-object-on-start.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Gosh! You found a ๐ŸŒต glitch
    Take me home
    + + + diff --git a/community/contributions/robyer1.html b/community/contributions/robyer1.html new file mode 100644 index 000000000..2a18a7561 --- /dev/null +++ b/community/contributions/robyer1.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Oh no โ€” this page does not exist!
    Take me home
    + + + diff --git a/community/contributions/robyer1/ar-move-scale-rotate-controls-for-needle-on-mobile.html b/community/contributions/robyer1/ar-move-scale-rotate-controls-for-needle-on-mobile.html new file mode 100644 index 000000000..4818fac8a --- /dev/null +++ b/community/contributions/robyer1/ar-move-scale-rotate-controls-for-needle-on-mobile.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Gosh! You found a ๐ŸŒต glitch
    Take me home
    + + + diff --git a/community/contributions/robyer1/microphone-access-in-a-browser-window-and-streamed-playback.html b/community/contributions/robyer1/microphone-access-in-a-browser-window-and-streamed-playback.html new file mode 100644 index 000000000..cf754eb78 --- /dev/null +++ b/community/contributions/robyer1/microphone-access-in-a-browser-window-and-streamed-playback.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Oh no โ€” this page does not exist!
    Take me home
    + + + diff --git a/community/contributions/web3kev.html b/community/contributions/web3kev.html new file mode 100644 index 000000000..522acacc4 --- /dev/null +++ b/community/contributions/web3kev.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Oh no โ€” this page does not exist!
    Take me home
    + + + diff --git a/community/contributions/web3kev/network-instantiation-of-multiple-objects.html b/community/contributions/web3kev/network-instantiation-of-multiple-objects.html new file mode 100644 index 000000000..ffd122a6f --- /dev/null +++ b/community/contributions/web3kev/network-instantiation-of-multiple-objects.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Oh no โ€” this page does not exist!
    Take me home
    + + + diff --git a/community/contributions/web3kev/squeeze-to-scale-object-or-world-in-vr.html b/community/contributions/web3kev/squeeze-to-scale-object-or-world-in-vr.html new file mode 100644 index 000000000..298f132a7 --- /dev/null +++ b/community/contributions/web3kev/squeeze-to-scale-object-or-world-in-vr.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Gosh! You found a ๐ŸŒต glitch
    Take me home
    + + + diff --git a/community/contributions/web3kev/vertical-move-in-vr-using-the-right-joystick-quest.html b/community/contributions/web3kev/vertical-move-in-vr-using-the-right-joystick-quest.html new file mode 100644 index 000000000..353bd2d1a --- /dev/null +++ b/community/contributions/web3kev/vertical-move-in-vr-using-the-right-joystick-quest.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +

    404

    Gosh! You found a ๐ŸŒต glitch
    Take me home
    + + + diff --git a/component-compiler.html b/component-compiler.html new file mode 100644 index 000000000..475c3bc1f --- /dev/null +++ b/component-compiler.html @@ -0,0 +1,146 @@ + + + + + + + + + Automatic Component Generation | Needle Engine Documentation + + + + + +
    + + + diff --git a/component-reference.html b/component-reference.html new file mode 100644 index 000000000..d0a5a05e5 --- /dev/null +++ b/component-reference.html @@ -0,0 +1,51 @@ + + + + + + + + + Needle Core Components | Needle Engine Documentation + + + + + +
    + + + diff --git a/custom-integrations/index.html b/custom-integrations/index.html new file mode 100644 index 000000000..f99c1329e --- /dev/null +++ b/custom-integrations/index.html @@ -0,0 +1,43 @@ + + + + + + + + + Integrate with other tools | Needle Engine Documentation + + + + + +
    + + + diff --git a/debugging.html b/debugging.html new file mode 100644 index 000000000..4b882446b --- /dev/null +++ b/debugging.html @@ -0,0 +1,56 @@ + + + + + + + + + How To Debug | Needle Engine Documentation + + + + + +
    + + + diff --git a/debugging/vscode-start-debugging.webp b/debugging/vscode-start-debugging.webp new file mode 100644 index 000000000..d523557d6 Binary files /dev/null and b/debugging/vscode-start-debugging.webp differ diff --git a/deployment.html b/deployment.html new file mode 100644 index 000000000..c48023ad1 --- /dev/null +++ b/deployment.html @@ -0,0 +1,48 @@ + + + + + + + + + Deployment and Optimization | Needle Engine Documentation + + + + + +
    + + + diff --git a/deployment/buildoptions_gzip.jpg b/deployment/buildoptions_gzip.jpg new file mode 100644 index 000000000..0472b9701 Binary files /dev/null and b/deployment/buildoptions_gzip.jpg differ diff --git a/deployment/deploytofacebookinstantgames-hosting.jpg b/deployment/deploytofacebookinstantgames-hosting.jpg new file mode 100644 index 000000000..63ef163c7 Binary files /dev/null and b/deployment/deploytofacebookinstantgames-hosting.jpg differ diff --git a/deployment/deploytofacebookinstantgames-upload.jpg b/deployment/deploytofacebookinstantgames-upload.jpg new file mode 100644 index 000000000..826fd6e5c Binary files /dev/null and b/deployment/deploytofacebookinstantgames-upload.jpg differ diff --git a/deployment/deploytofacebookinstantgames.jpg b/deployment/deploytofacebookinstantgames.jpg new file mode 100644 index 000000000..d0dfb4107 Binary files /dev/null and b/deployment/deploytofacebookinstantgames.jpg differ diff --git a/deployment/deploytoftp.jpg b/deployment/deploytoftp.jpg new file mode 100644 index 000000000..85ae4b87f Binary files /dev/null and b/deployment/deploytoftp.jpg differ diff --git a/deployment/deploytoftp2.jpg b/deployment/deploytoftp2.jpg new file mode 100644 index 000000000..16d1173de Binary files /dev/null and b/deployment/deploytoftp2.jpg differ diff --git a/deployment/deploytoftp3.jpg b/deployment/deploytoftp3.jpg new file mode 100644 index 000000000..cb7a1f242 Binary files /dev/null and b/deployment/deploytoftp3.jpg differ diff --git a/deployment/deploytogithubpages.jpg b/deployment/deploytogithubpages.jpg new file mode 100644 index 000000000..19978c16b Binary files /dev/null and b/deployment/deploytogithubpages.jpg differ diff --git a/deployment/deploytoglitch-1.jpg b/deployment/deploytoglitch-1.jpg new file mode 100644 index 000000000..c45bcd0ee Binary files /dev/null and b/deployment/deploytoglitch-1.jpg differ diff --git a/deployment/deploytoglitch-2.jpg b/deployment/deploytoglitch-2.jpg new file mode 100644 index 000000000..35c3e40d6 Binary files /dev/null and b/deployment/deploytoglitch-2.jpg differ diff --git a/deployment/deploytonetlify-2.jpg b/deployment/deploytonetlify-2.jpg new file mode 100644 index 000000000..30f80f9ab Binary files /dev/null and b/deployment/deploytonetlify-2.jpg differ diff --git a/deployment/deploytonetlify.jpg b/deployment/deploytonetlify.jpg new file mode 100644 index 000000000..e56f2ed5c Binary files /dev/null and b/deployment/deploytonetlify.jpg differ diff --git a/deployment/facebookinstantgames-1.jpg b/deployment/facebookinstantgames-1.jpg new file mode 100644 index 000000000..7e7ebdc6e Binary files /dev/null and b/deployment/facebookinstantgames-1.jpg differ diff --git a/deployment/facebookinstantgames-2.jpg b/deployment/facebookinstantgames-2.jpg new file mode 100644 index 000000000..122a3dbb0 Binary files /dev/null and b/deployment/facebookinstantgames-2.jpg differ diff --git a/deployment/facebookinstantgames-3.jpg b/deployment/facebookinstantgames-3.jpg new file mode 100644 index 000000000..4157da4d6 Binary files /dev/null and b/deployment/facebookinstantgames-3.jpg differ diff --git a/embedding.html b/embedding.html new file mode 100644 index 000000000..1cd5a5745 --- /dev/null +++ b/embedding.html @@ -0,0 +1,58 @@ + + + + + + + + + Needle Engine on your Website | Needle Engine Documentation + + + + + +
    + + + diff --git a/everywhere-actions.html b/everywhere-actions.html new file mode 100644 index 000000000..09b5e00df --- /dev/null +++ b/everywhere-actions.html @@ -0,0 +1,72 @@ + + + + + + + + + Everywhere Actions | Needle Engine Documentation + + + + + +
    + + + diff --git a/examples.html b/examples.html new file mode 100644 index 000000000..f5162118d --- /dev/null +++ b/examples.html @@ -0,0 +1,43 @@ + + + + + + + + + Example Projects โœจ | Needle Engine Documentation + + + + + +
    + + + diff --git a/export.html b/export.html new file mode 100644 index 000000000..fae0a5edc --- /dev/null +++ b/export.html @@ -0,0 +1,87 @@ + + + + + + + + + Exporting Assets to glTF | Needle Engine Documentation + + + + + +
    + + + diff --git a/faq.html b/faq.html new file mode 100644 index 000000000..04f446495 --- /dev/null +++ b/faq.html @@ -0,0 +1,53 @@ + + + + + + + + + Questions and Answers (FAQ) ๐Ÿ’ก | Needle Engine Documentation + + + + + +
    + + + diff --git a/faq/lightmap_encoding.jpg b/faq/lightmap_encoding.jpg new file mode 100644 index 000000000..a1b8a6222 Binary files /dev/null and b/faq/lightmap_encoding.jpg differ diff --git a/features-overview.html b/features-overview.html new file mode 100644 index 000000000..39ad1449a --- /dev/null +++ b/features-overview.html @@ -0,0 +1,43 @@ + + + + + + + + + Feature Overview | Needle Engine Documentation + + + + + +
    + + + diff --git a/for-unity-developers.html b/for-unity-developers.html new file mode 100644 index 000000000..578641763 --- /dev/null +++ b/for-unity-developers.html @@ -0,0 +1,43 @@ + + + + + + + + + Scripting basics For Unity Developers | Needle Engine Documentation + + + + + +
    + + + diff --git a/getting-started.html b/getting-started.html new file mode 100644 index 000000000..4d57a22e5 --- /dev/null +++ b/getting-started.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +
    + + + diff --git a/getting-started/for-unity-developers.html b/getting-started/for-unity-developers.html new file mode 100644 index 000000000..9360521c2 --- /dev/null +++ b/getting-started/for-unity-developers.html @@ -0,0 +1,176 @@ + + + + + + + + + Scripting Introduction for Unity Developers | Needle Engine Documentation + + + + + +
    + + + diff --git a/getting-started/index.html b/getting-started/index.html new file mode 100644 index 000000000..37ebfe108 --- /dev/null +++ b/getting-started/index.html @@ -0,0 +1,49 @@ + + + + + + + + + Getting Started & Installation | Needle Engine Documentation + + + + + +
    + + + diff --git a/getting-started/typescript-essentials.html b/getting-started/typescript-essentials.html new file mode 100644 index 000000000..12dcc406e --- /dev/null +++ b/getting-started/typescript-essentials.html @@ -0,0 +1,141 @@ + + + + + + + + + Scripting in Needle Engine | Needle Engine Documentation + + + + + +
    + + + diff --git a/html.html b/html.html new file mode 100644 index 000000000..518421ccd --- /dev/null +++ b/html.html @@ -0,0 +1,81 @@ + + + + + + + + + Frameworks, Bundlers, HTML | Needle Engine Documentation + + + + + +
    + + + diff --git a/icons/android-chrome-144x144.png b/icons/android-chrome-144x144.png new file mode 100644 index 000000000..9680622fd Binary files /dev/null and b/icons/android-chrome-144x144.png differ diff --git a/icons/apple-touch-icon.png b/icons/apple-touch-icon.png new file mode 100644 index 000000000..2d25b4f84 Binary files /dev/null and b/icons/apple-touch-icon.png differ diff --git a/icons/browserconfig.xml b/icons/browserconfig.xml new file mode 100644 index 000000000..b3930d0f0 --- /dev/null +++ b/icons/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #da532c + + + diff --git a/icons/favicon-16x16.png b/icons/favicon-16x16.png new file mode 100644 index 000000000..83022bbdd Binary files /dev/null and b/icons/favicon-16x16.png differ diff --git a/icons/favicon-32x32.png b/icons/favicon-32x32.png new file mode 100644 index 000000000..9835e8bbe Binary files /dev/null and b/icons/favicon-32x32.png differ diff --git a/icons/favicon.ico b/icons/favicon.ico new file mode 100644 index 000000000..974434168 Binary files /dev/null and b/icons/favicon.ico differ diff --git a/icons/mstile-150x150.png b/icons/mstile-150x150.png new file mode 100644 index 000000000..d3610882f Binary files /dev/null and b/icons/mstile-150x150.png differ diff --git a/icons/safari-pinned-tab.svg b/icons/safari-pinned-tab.svg new file mode 100644 index 000000000..f36a1bd6a --- /dev/null +++ b/icons/safari-pinned-tab.svg @@ -0,0 +1,27 @@ + + + + +Created by potrace 1.14, written by Peter Selinger 2001-2017 + + + + + + + diff --git a/imgs/banner.webp b/imgs/banner.webp new file mode 100644 index 000000000..9c60ec03a Binary files /dev/null and b/imgs/banner.webp differ diff --git a/imgs/custom-loading-style.webp b/imgs/custom-loading-style.webp new file mode 100644 index 000000000..ae2bba3ff Binary files /dev/null and b/imgs/custom-loading-style.webp differ diff --git a/imgs/everywhere-actions-component-menu.gif b/imgs/everywhere-actions-component-menu.gif new file mode 100644 index 000000000..88ab8c6d4 Binary files /dev/null and b/imgs/everywhere-actions-component-menu.gif differ diff --git a/imgs/ktx-env-variable.webp b/imgs/ktx-env-variable.webp new file mode 100644 index 000000000..f4c9e624a Binary files /dev/null and b/imgs/ktx-env-variable.webp differ diff --git a/imgs/logo-webcomponents.png b/imgs/logo-webcomponents.png new file mode 100644 index 000000000..3ed870741 Binary files /dev/null and b/imgs/logo-webcomponents.png differ diff --git a/imgs/networking_absolute.webp b/imgs/networking_absolute.webp new file mode 100644 index 000000000..f0adeb1e7 Binary files /dev/null and b/imgs/networking_absolute.webp differ diff --git a/imgs/threejs-logo.webp b/imgs/threejs-logo.webp new file mode 100644 index 000000000..ec0969905 Binary files /dev/null and b/imgs/threejs-logo.webp differ diff --git a/imgs/unity-build-window-menu.jpg b/imgs/unity-build-window-menu.jpg new file mode 100644 index 000000000..863cab49d Binary files /dev/null and b/imgs/unity-build-window-menu.jpg differ diff --git a/imgs/unity-build-window.jpg b/imgs/unity-build-window.jpg new file mode 100644 index 000000000..50b91cd4b Binary files /dev/null and b/imgs/unity-build-window.jpg differ diff --git a/imgs/unity-lods-settings-1.jpg b/imgs/unity-lods-settings-1.jpg new file mode 100644 index 000000000..8fd711a9a Binary files /dev/null and b/imgs/unity-lods-settings-1.jpg differ diff --git a/imgs/unity-lods-settings-2.jpg b/imgs/unity-lods-settings-2.jpg new file mode 100644 index 000000000..203fface5 Binary files /dev/null and b/imgs/unity-lods-settings-2.jpg differ diff --git a/imgs/unity-logo.webp b/imgs/unity-logo.webp new file mode 100644 index 000000000..94b943ad6 Binary files /dev/null and b/imgs/unity-logo.webp differ diff --git a/imgs/unity-mesh-compression-component.jpg b/imgs/unity-mesh-compression-component.jpg new file mode 100644 index 000000000..f68b7ac17 Binary files /dev/null and b/imgs/unity-mesh-compression-component.jpg differ diff --git a/imgs/unity-mesh-simplification.jpg b/imgs/unity-mesh-simplification.jpg new file mode 100644 index 000000000..4c3a4b11d Binary files /dev/null and b/imgs/unity-mesh-simplification.jpg differ diff --git a/imgs/unity-needle-engine-license.jpg b/imgs/unity-needle-engine-license.jpg new file mode 100644 index 000000000..6475feb07 Binary files /dev/null and b/imgs/unity-needle-engine-license.jpg differ diff --git a/imgs/unity-needle-engine-modules-physics.jpg b/imgs/unity-needle-engine-modules-physics.jpg new file mode 100644 index 000000000..164aff107 Binary files /dev/null and b/imgs/unity-needle-engine-modules-physics.jpg differ diff --git a/imgs/unity-progressive-textures.jpg b/imgs/unity-progressive-textures.jpg new file mode 100644 index 000000000..37e576f0c Binary files /dev/null and b/imgs/unity-progressive-textures.jpg differ diff --git a/imgs/unity-project-local-template.jpg b/imgs/unity-project-local-template.jpg new file mode 100644 index 000000000..fb1ca1959 Binary files /dev/null and b/imgs/unity-project-local-template.jpg differ diff --git a/imgs/unity-project-remote-template.jpg b/imgs/unity-project-remote-template.jpg new file mode 100644 index 000000000..d2c566d9b Binary files /dev/null and b/imgs/unity-project-remote-template.jpg differ diff --git a/imgs/unity-texture-compression-options.jpg b/imgs/unity-texture-compression-options.jpg new file mode 100644 index 000000000..790887490 Binary files /dev/null and b/imgs/unity-texture-compression-options.jpg differ diff --git a/imgs/unity-texture-compression.jpg b/imgs/unity-texture-compression.jpg new file mode 100644 index 000000000..2c1f9a03a Binary files /dev/null and b/imgs/unity-texture-compression.jpg differ diff --git a/index.html b/index.html new file mode 100644 index 000000000..32d4626fc --- /dev/null +++ b/index.html @@ -0,0 +1,49 @@ + + + + + + + + + Needle Engine Documentation + + + + + +
    + + + diff --git a/logo.png b/logo.png new file mode 100644 index 000000000..88ea1adf4 Binary files /dev/null and b/logo.png differ diff --git a/manifest.webmanifest b/manifest.webmanifest new file mode 100644 index 000000000..9daf50f46 --- /dev/null +++ b/manifest.webmanifest @@ -0,0 +1,15 @@ +{ + "id" : "needle_engine_docs", + "name": "Needle Engine Documentation", + "short_name": "Needle Engine Docs", + "description": "Needle Engine is a web-based runtime for 3D apps", + "start_url": "/docs/index.html", + "display": "standalone", + "icons": [ + { + "src": "https://engine.needle.tools/docs/android-chrome-144x144.png", + "sizes": "144x144", + "type": "image/png" + } + ] + } \ No newline at end of file diff --git a/meta-test.html b/meta-test.html new file mode 100644 index 000000000..b37742779 --- /dev/null +++ b/meta-test.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine Documentation + + + + + +
    + + + diff --git a/meta/samples.json b/meta/samples.json new file mode 100644 index 000000000..1fbe65c2f --- /dev/null +++ b/meta/samples.json @@ -0,0 +1 @@ +{"webxr":[{"name":"webxr","page":"_meta-test","anchor":"my-test-header","absolute-url":"https://engine.needle.tools/docs/_meta-test#my-test-header","description":"here is a description","tags":["webxr","webgl","augmented reality"]}],"ui canvas":[{"name":"ui canvas","page":"_meta-test","anchor":"ui-canvas","absolute-url":"https://engine.needle.tools/docs/_meta-test#ui-canvas","description":"this is a description about UI","tags":["hello world"]}],"physics playground":[{"name":"physics playground","page":"_meta-test","anchor":"how-physics-works","absolute-url":"https://engine.needle.tools/docs/_meta-test#how-physics-works","tags":["physics"]}],"another sample":[{"name":"another sample","page":"_meta-test","anchor":"how-physics-works","absolute-url":"https://engine.needle.tools/docs/_meta-test#how-physics-works","tags":["physics"]}]} \ No newline at end of file diff --git a/meta/tags.json b/meta/tags.json new file mode 100644 index 000000000..b261d6ce5 --- /dev/null +++ b/meta/tags.json @@ -0,0 +1 @@ +{"codegen":[{"page":"component-compiler","anchor":"automatically-generating-editor-components","absolute-url":"https://engine.needle.tools/docs/component-compiler#automatically-generating-editor-components"},{"page":"component-compiler","anchor":"controlling-component-generation","absolute-url":"https://engine.needle.tools/docs/component-compiler#controlling-component-generation"}],"webxr":[{"page":"_meta-test","anchor":"my-test-header","absolute-url":"https://engine.needle.tools/docs/_meta-test#my-test-header"}],"webgl":[{"page":"_meta-test","anchor":"my-test-header","absolute-url":"https://engine.needle.tools/docs/_meta-test#my-test-header"}],"augmented reality":[{"page":"_meta-test","anchor":"my-test-header","absolute-url":"https://engine.needle.tools/docs/_meta-test#my-test-header"}],"hello world":[{"page":"_meta-test","anchor":"ui-canvas","absolute-url":"https://engine.needle.tools/docs/_meta-test#ui-canvas"}],"physics":[{"page":"_meta-test","anchor":"how-physics-works","absolute-url":"https://engine.needle.tools/docs/_meta-test#how-physics-works"}],"serialization":[{"page":"scripting","anchor":"serialization-components-in-gltf-files","absolute-url":"https://engine.needle.tools/docs/scripting#serialization-components-in-gltf-files"}]} \ No newline at end of file diff --git a/modules.html b/modules.html new file mode 100644 index 000000000..d32bb71cb --- /dev/null +++ b/modules.html @@ -0,0 +1,47 @@ + + + + + + + + + Additional Modules | Needle Engine Documentation + + + + + +
    + + + diff --git a/needle-logo-black.svg b/needle-logo-black.svg new file mode 100644 index 000000000..9bd940710 --- /dev/null +++ b/needle-logo-black.svg @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/needle-logo-white.svg b/needle-logo-white.svg new file mode 100644 index 000000000..9f3943268 --- /dev/null +++ b/needle-logo-white.svg @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/networking.html b/networking.html new file mode 100644 index 000000000..14d69a59c --- /dev/null +++ b/networking.html @@ -0,0 +1,104 @@ + + + + + + + + + Networking | Needle Engine Documentation + + + + + +
    + + + diff --git a/preview.jpeg b/preview.jpeg new file mode 100644 index 000000000..814a087c3 Binary files /dev/null and b/preview.jpeg differ diff --git a/project-structure.html b/project-structure.html new file mode 100644 index 000000000..539c0cdff --- /dev/null +++ b/project-structure.html @@ -0,0 +1,43 @@ + + + + + + + + + Web Project Structure | Needle Engine Documentation + + + + + +
    + + + diff --git a/reference/needle-config-json.html b/reference/needle-config-json.html new file mode 100644 index 000000000..8c85f05b0 --- /dev/null +++ b/reference/needle-config-json.html @@ -0,0 +1,66 @@ + + + + + + + + + needle.config.json | Needle Engine Documentation + + + + + +
    + + + diff --git a/reference/needle-engine-attributes.html b/reference/needle-engine-attributes.html new file mode 100644 index 000000000..248c5a3be --- /dev/null +++ b/reference/needle-engine-attributes.html @@ -0,0 +1,60 @@ + + + + + + + + + <needle-engine> Configuration | Needle Engine Documentation + + + + + +
    + + + diff --git a/reference/typescript-decorators.html b/reference/typescript-decorators.html new file mode 100644 index 000000000..761aaf014 --- /dev/null +++ b/reference/typescript-decorators.html @@ -0,0 +1,102 @@ + + + + + + + + + @serializable and other decorators | Needle Engine Documentation + + + + + +
    + + + diff --git a/samples-and-modules.html b/samples-and-modules.html new file mode 100644 index 000000000..5def548a7 --- /dev/null +++ b/samples-and-modules.html @@ -0,0 +1,47 @@ + + + + + + + + + Samples Projects | Needle Engine Documentation + + + + + +
    + + + diff --git a/scripting-examples.html b/scripting-examples.html new file mode 100644 index 000000000..91aa89bb8 --- /dev/null +++ b/scripting-examples.html @@ -0,0 +1,763 @@ + + + + + + + + + Scripting Examples | Needle Engine Documentation + + + + + +
    + + + diff --git a/scripting.html b/scripting.html new file mode 100644 index 000000000..cea5b1348 --- /dev/null +++ b/scripting.html @@ -0,0 +1,210 @@ + + + + + + + + + Creating and using Components | Needle Engine Documentation + + + + + +
    + + + diff --git a/showcase-bike.html b/showcase-bike.html new file mode 100644 index 000000000..2868fd169 --- /dev/null +++ b/showcase-bike.html @@ -0,0 +1,45 @@ + + + + + + + + + Bike Configurator ๐Ÿšฒ | Needle Engine Documentation + + + + + +
    + + + diff --git a/showcase-castle.html b/showcase-castle.html new file mode 100644 index 000000000..92db143e2 --- /dev/null +++ b/showcase-castle.html @@ -0,0 +1,53 @@ + + + + + + + + + Castle Builder ๐Ÿฐ | Needle Engine Documentation + + + + + +
    + + + diff --git a/showcase-mercedes-benz.html b/showcase-mercedes-benz.html new file mode 100644 index 000000000..67ad310f6 --- /dev/null +++ b/showcase-mercedes-benz.html @@ -0,0 +1,89 @@ + + + + + + + + + Mercedes-Benz Showcase | Needle Engine Documentation + + + + + +
    + + + diff --git a/showcase-mercedes/10_WheelsAndGrid.png b/showcase-mercedes/10_WheelsAndGrid.png new file mode 100644 index 000000000..869772b0b Binary files /dev/null and b/showcase-mercedes/10_WheelsAndGrid.png differ diff --git a/showcase-mercedes/11_GridShader.jpg b/showcase-mercedes/11_GridShader.jpg new file mode 100644 index 000000000..8aa5c8dd7 Binary files /dev/null and b/showcase-mercedes/11_GridShader.jpg differ diff --git a/showcase-mercedes/12_WheelWithText.png b/showcase-mercedes/12_WheelWithText.png new file mode 100644 index 000000000..a2973ab3d Binary files /dev/null and b/showcase-mercedes/12_WheelWithText.png differ diff --git a/showcase-mercedes/13_WheelShader.jpg b/showcase-mercedes/13_WheelShader.jpg new file mode 100644 index 000000000..fcf52ad50 Binary files /dev/null and b/showcase-mercedes/13_WheelShader.jpg differ diff --git a/showcase-mercedes/14_RearUI.jpg b/showcase-mercedes/14_RearUI.jpg new file mode 100644 index 000000000..35949e338 Binary files /dev/null and b/showcase-mercedes/14_RearUI.jpg differ diff --git a/showcase-mercedes/1_skybox.png b/showcase-mercedes/1_skybox.png new file mode 100644 index 000000000..4611373a0 Binary files /dev/null and b/showcase-mercedes/1_skybox.png differ diff --git a/showcase-mercedes/2_paintjob_simple.jpg b/showcase-mercedes/2_paintjob_simple.jpg new file mode 100644 index 000000000..e5be417b3 Binary files /dev/null and b/showcase-mercedes/2_paintjob_simple.jpg differ diff --git a/showcase-mercedes/3_SpecularHighlights_off.jpg b/showcase-mercedes/3_SpecularHighlights_off.jpg new file mode 100644 index 000000000..bdc2aa805 Binary files /dev/null and b/showcase-mercedes/3_SpecularHighlights_off.jpg differ diff --git a/showcase-mercedes/4_SpecularHighlights_on.jpg b/showcase-mercedes/4_SpecularHighlights_on.jpg new file mode 100644 index 000000000..fad273a28 Binary files /dev/null and b/showcase-mercedes/4_SpecularHighlights_on.jpg differ diff --git a/showcase-mercedes/5_NoBackground.jpg b/showcase-mercedes/5_NoBackground.jpg new file mode 100644 index 000000000..7f607b9de Binary files /dev/null and b/showcase-mercedes/5_NoBackground.jpg differ diff --git a/showcase-mercedes/6_MapBackground.png b/showcase-mercedes/6_MapBackground.png new file mode 100644 index 000000000..e17bd6117 Binary files /dev/null and b/showcase-mercedes/6_MapBackground.png differ diff --git a/showcase-mercedes/7_EnvShaderGraph.jpg b/showcase-mercedes/7_EnvShaderGraph.jpg new file mode 100644 index 000000000..3d91713dd Binary files /dev/null and b/showcase-mercedes/7_EnvShaderGraph.jpg differ diff --git a/showcase-mercedes/8_Gradiant.png b/showcase-mercedes/8_Gradiant.png new file mode 100644 index 000000000..e68c7984e Binary files /dev/null and b/showcase-mercedes/8_Gradiant.png differ diff --git a/showcase-mercedes/9_Rotator.png b/showcase-mercedes/9_Rotator.png new file mode 100644 index 000000000..8ca66499d Binary files /dev/null and b/showcase-mercedes/9_Rotator.png differ diff --git a/showcase-monsterhands.html b/showcase-monsterhands.html new file mode 100644 index 000000000..a573a9284 --- /dev/null +++ b/showcase-monsterhands.html @@ -0,0 +1,45 @@ + + + + + + + + + Monster Hands ๐Ÿ’€ | Needle Engine Documentation + + + + + +
    + + + diff --git a/showcase-towerdefence.html b/showcase-towerdefence.html new file mode 100644 index 000000000..63476ed67 --- /dev/null +++ b/showcase-towerdefence.html @@ -0,0 +1,45 @@ + + + + + + + + + Tower Defense | Needle Engine Documentation + + + + + +
    + + + diff --git a/showcase-website.html b/showcase-website.html new file mode 100644 index 000000000..3e767cac7 --- /dev/null +++ b/showcase-website.html @@ -0,0 +1,45 @@ + + + + + + + + + Castle Builder ๐Ÿฐ | Needle Engine Documentation + + + + + +
    + + + diff --git a/showcase-zenrepublic.html b/showcase-zenrepublic.html new file mode 100644 index 000000000..cd90f5afa --- /dev/null +++ b/showcase-zenrepublic.html @@ -0,0 +1,45 @@ + + + + + + + + + Monster Hands ๐Ÿ’€ | Needle Engine Documentation + + + + + +
    + + + diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 000000000..c405cfc46 --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,3 @@ + + +https://engine.needle.tools/docs/SUMMARY.html2024-09-16T11:53:09.000Zdailyhttps://engine.needle.tools/docs/backlog-mermaid.html2022-10-24T09:26:03.000Zdailyhttps://engine.needle.tools/docs/backlog.html2022-11-29T23:14:22.000Zdailyhttps://engine.needle.tools/docs/meta-test.html2022-12-18T13:36:22.000Zdailyhttps://engine.needle.tools/docs/component-compiler.html2024-09-16T19:23:57.000Zdailyhttps://engine.needle.tools/docs/component-reference.html2024-09-24T12:54:20.000Zdailyhttps://engine.needle.tools/docs/debugging.html2023-11-23T07:31:12.000Zdailyhttps://engine.needle.tools/docs/deployment.html2024-09-03T21:36:19.000Zdailyhttps://engine.needle.tools/docs/embedding.html2024-10-01T10:22:56.000Zdailyhttps://engine.needle.tools/docs/everywhere-actions.html2024-09-17T14:59:55.000Zdailyhttps://engine.needle.tools/docs/examples.html2024-09-17T20:47:45.000Zdailyhttps://engine.needle.tools/docs/export.html2024-09-17T14:59:55.000Zdailyhttps://engine.needle.tools/docs/faq.html2024-09-23T21:10:36.000Zdailyhttps://engine.needle.tools/docs/features-overview.html2024-09-23T21:10:36.000Zdailyhttps://engine.needle.tools/docs/for-unity-developers.html2024-09-03T21:36:19.000Zdailyhttps://engine.needle.tools/docs/getting-started.html2024-09-23T21:10:36.000Zdailyhttps://engine.needle.tools/docs/html.html2024-09-03T21:36:19.000Zdailyhttps://engine.needle.tools/docs/2024-09-24T15:31:25.000Zdailyhttps://engine.needle.tools/docs/modules.html2024-09-03T21:36:19.000Zdailyhttps://engine.needle.tools/docs/networking.html2024-09-17T14:59:55.000Zdailyhttps://engine.needle.tools/docs/project-structure.html2024-09-30T19:04:15.000Zdailyhttps://engine.needle.tools/docs/samples-and-modules.html2024-02-12T19:02:48.000Zdailyhttps://engine.needle.tools/docs/scripting-examples.html2024-09-17T20:47:45.000Zdailyhttps://engine.needle.tools/docs/scripting.html2024-09-17T14:59:55.000Zdailyhttps://engine.needle.tools/docs/showcase-bike.html2022-11-29T23:14:22.000Zdailyhttps://engine.needle.tools/docs/showcase-castle.html2022-11-29T23:14:22.000Zdailyhttps://engine.needle.tools/docs/showcase-mercedes-benz.html2024-09-17T14:59:55.000Zdailyhttps://engine.needle.tools/docs/showcase-monsterhands.html2023-04-26T08:27:06.000Zdailyhttps://engine.needle.tools/docs/showcase-towerdefence.html2023-05-20T14:26:00.000Zdailyhttps://engine.needle.tools/docs/showcase-website.html2022-11-29T23:14:22.000Zdailyhttps://engine.needle.tools/docs/showcase-zenrepublic.html2023-04-26T08:27:06.000Zdailyhttps://engine.needle.tools/docs/support.html2024-09-30T07:38:31.000Zdailyhttps://engine.needle.tools/docs/technical-overview.html2024-09-03T21:36:19.000Zdailyhttps://engine.needle.tools/docs/testimonials.html2024-09-23T21:10:36.000Zdailyhttps://engine.needle.tools/docs/testing.html2023-07-12T15:39:44.000Zdailyhttps://engine.needle.tools/docs/vanilla-js.html2024-09-24T12:54:20.000Zdailyhttps://engine.needle.tools/docs/vision.html2022-10-29T20:26:52.000Zdailyhttps://engine.needle.tools/docs/xr.html2024-09-11T20:32:55.000Zdailyhttps://engine.needle.tools/docs/blender/2024-09-24T12:54:20.000Zdailyhttps://engine.needle.tools/docs/custom-integrations/2024-09-24T12:54:20.000Zdailyhttps://engine.needle.tools/docs/getting-started/for-unity-developers.html2024-09-17T14:59:55.000Zdailyhttps://engine.needle.tools/docs/getting-started/2024-09-24T14:53:16.000Zdailyhttps://engine.needle.tools/docs/getting-started/typescript-essentials.html2024-09-17T14:59:55.000Zdailyhttps://engine.needle.tools/docs/reference/needle-config-json.html2024-09-03T21:36:19.000Zdailyhttps://engine.needle.tools/docs/reference/needle-engine-attributes.html2024-09-24T10:02:35.000Zdailyhttps://engine.needle.tools/docs/reference/typescript-decorators.html2024-09-17T14:59:55.000Zdailyhttps://engine.needle.tools/docs/three/2024-09-30T14:39:50.000Zdailyhttps://engine.needle.tools/docs/unity/editor-sync.html2024-09-23T15:48:04.000Zdailyhttps://engine.needle.tools/docs/unity/2024-09-24T12:54:20.000Zdailyhttps://engine.needle.tools/docs/community/contributions/llllkatjallll/custom-vr-button-that-appears-only-on-headsets-and-not-on-mobile-phonesdailyhttps://engine.needle.tools/docs/community/contributions/llllkatjallll/set-fallback-material-for-usdz-exporterdailyhttps://engine.needle.tools/docs/community/contributions/llllkatjalllldailyhttps://engine.needle.tools/docs/community/contributions/robyer1/microphone-access-in-a-browser-window-and-streamed-playbackdailyhttps://engine.needle.tools/docs/community/contributions/robyer1/ar-move-scale-rotate-controls-for-needle-on-mobiledailyhttps://engine.needle.tools/docs/community/contributions/robyer1dailyhttps://engine.needle.tools/docs/community/contributions/ericcraft-mh/quicklook-vertical-image-trackerdailyhttps://engine.needle.tools/docs/community/contributions/ericcraft-mhdailyhttps://engine.needle.tools/docs/community/contributions/krisrok/always-open-in-specific-browserdailyhttps://engine.needle.tools/docs/community/contributions/krisrokdailyhttps://engine.needle.tools/docs/community/contributions/marwie/camera-video-backgrounddailyhttps://engine.needle.tools/docs/community/contributions/marwie/usdz-hide-object-on-startdailyhttps://engine.needle.tools/docs/community/contributions/marwie/everywhere-action-emphasize-on-clickdailyhttps://engine.needle.tools/docs/community/contributions/marwie/control-a-timeline-by-scrolldailyhttps://engine.needle.tools/docs/community/contributions/marwie/code-contribution-exampledailyhttps://engine.needle.tools/docs/community/contributions/marwiedailyhttps://engine.needle.tools/docs/community/contributions/kipash/calculate-pointer-world-positiondailyhttps://engine.needle.tools/docs/community/contributions/kipashdailyhttps://engine.needle.tools/docs/community/contributions/web3kev/vertical-move-in-vr-using-the-right-joystick-questdailyhttps://engine.needle.tools/docs/community/contributions/web3kev/squeeze-to-scale-object-or-world-in-vrdailyhttps://engine.needle.tools/docs/community/contributions/web3kev/network-instantiation-of-multiple-objectsdailyhttps://engine.needle.tools/docs/community/contributions/web3kevdailyhttps://engine.needle.tools/docs/community/contributionsdaily \ No newline at end of file diff --git a/sitemap.xsl b/sitemap.xsl new file mode 100644 index 000000000..a76881a48 --- /dev/null +++ b/sitemap.xsl @@ -0,0 +1,207 @@ + + + + + + + XML Sitemap + + + + + +
    +

    Sitemap

    + + + + + + + + + + + + + + + + + + + + + +
    + + PriorityChange FrequencyLast Updated Time
    + + + + + + + + + + + + + 0.5 + + + + + + + + + - + + + + +
    +
    + + + +
    +
    diff --git a/support.html b/support.html new file mode 100644 index 000000000..22ae1be89 --- /dev/null +++ b/support.html @@ -0,0 +1,43 @@ + + + + + + + + + Support and Community | Needle Engine Documentation + + + + + +
    + + + diff --git a/technical-overview.html b/technical-overview.html new file mode 100644 index 000000000..ff7378be6 --- /dev/null +++ b/technical-overview.html @@ -0,0 +1,296 @@ + + + + + + + + + Technical Overview | Needle Engine Documentation + + + + + +
    + + + diff --git a/testimonials.html b/testimonials.html new file mode 100644 index 000000000..65daac721 --- /dev/null +++ b/testimonials.html @@ -0,0 +1,45 @@ + + + + + + + + + Testimonials | Needle Engine Documentation + + + + + +
    + + + diff --git a/testing.html b/testing.html new file mode 100644 index 000000000..65dfb2214 --- /dev/null +++ b/testing.html @@ -0,0 +1,71 @@ + + + + + + + + + Testing on local devices | Needle Engine Documentation + + + + + +
    + + + diff --git a/testing/switch-to-mkcert.webp b/testing/switch-to-mkcert.webp new file mode 100644 index 000000000..dee32c704 Binary files /dev/null and b/testing/switch-to-mkcert.webp differ diff --git a/three/index.html b/three/index.html new file mode 100644 index 000000000..67d5d18ec --- /dev/null +++ b/three/index.html @@ -0,0 +1,115 @@ + + + + + + + + + Needle Engine as Web Component | Needle Engine Documentation + + + + + +
    + + + diff --git a/unity/editor-sync.html b/unity/editor-sync.html new file mode 100644 index 000000000..a9817ecca --- /dev/null +++ b/unity/editor-sync.html @@ -0,0 +1,43 @@ + + + + + + + + + Editor Sync | Needle Engine Documentation + + + + + +
    + + + diff --git a/unity/index.html b/unity/index.html new file mode 100644 index 000000000..a0c094edf --- /dev/null +++ b/unity/index.html @@ -0,0 +1,43 @@ + + + + + + + + + Needle Engine for Unity | Needle Engine Documentation + + + + + +
    + + + diff --git a/vanilla-js.html b/vanilla-js.html new file mode 100644 index 000000000..c7a65358f --- /dev/null +++ b/vanilla-js.html @@ -0,0 +1,45 @@ + + + + + + + + + Using Needle Engine directly from HTML | Needle Engine Documentation + + + + + +
    + + + diff --git a/videos/component-time.mp4 b/videos/component-time.mp4 new file mode 100644 index 000000000..964f8dbb4 Binary files /dev/null and b/videos/component-time.mp4 differ diff --git a/vision.html b/vision.html new file mode 100644 index 000000000..5080497e0 --- /dev/null +++ b/vision.html @@ -0,0 +1,57 @@ + + + + + + + + + Our Vision ๐Ÿ”ฎ | Needle Engine Documentation + + + + + +
    + + + diff --git a/xr.html b/xr.html new file mode 100644 index 000000000..967bbc8c4 --- /dev/null +++ b/xr.html @@ -0,0 +1,58 @@ + + + + + + + + + VR & AR (WebXR) | Needle Engine Documentation + + + + + +
    + + +