├── .gitignore ├── LICENSE ├── README.md ├── dist ├── Horse.glb ├── Idle.fbx ├── assets │ ├── CanvasWorker-CkVXIHwP.js │ ├── LoadWorker-Dqroi5Gd.js │ ├── index-CjSOBxjP.css │ └── index-DqirLK5_.js ├── cube │ ├── nx.png │ ├── ny.png │ ├── nz.png │ ├── px.png │ ├── py.png │ └── pz.png ├── index.html ├── libs │ └── draco │ │ ├── README.md │ │ ├── draco_decoder.js │ │ ├── draco_decoder.wasm │ │ ├── draco_encoder.js │ │ ├── draco_wasm_wrapper.js │ │ └── gltf │ │ ├── draco_decoder.js │ │ ├── draco_decoder.wasm │ │ ├── draco_encoder.js │ │ └── draco_wasm_wrapper.js ├── uvGrid.jpg └── vite.svg ├── eslint.config.js ├── index.html ├── package.json ├── public ├── Horse.glb ├── Idle.fbx ├── cube │ ├── nx.png │ ├── ny.png │ ├── nz.png │ ├── px.png │ ├── py.png │ └── pz.png ├── libs │ └── draco │ │ ├── README.md │ │ ├── draco_decoder.js │ │ ├── draco_decoder.wasm │ │ ├── draco_encoder.js │ │ ├── draco_wasm_wrapper.js │ │ └── gltf │ │ ├── draco_decoder.js │ │ ├── draco_decoder.wasm │ │ ├── draco_encoder.js │ │ └── draco_wasm_wrapper.js ├── uvGrid.jpg └── vite.svg ├── src ├── Wrapper.tsx ├── canvas │ ├── CanvasComponent.tsx │ ├── OffscreenWay.tsx │ └── StandardWay.tsx ├── components │ └── Loader.tsx ├── global │ ├── constants.ts │ └── settings.ts ├── index.css ├── main.tsx ├── types.ts ├── vite-env.d.ts ├── webgl │ ├── ThreeApp.ts │ ├── ThreeScene.ts │ └── threeUtils.ts └── webworker │ ├── CanvasWorker.ts │ ├── EventHandling.ts │ ├── LoadWorker.ts │ ├── ProxyManager.ts │ └── workers.ts ├── tsconfig.app.json ├── tsconfig.json ├── tsconfig.node.json ├── vite.config.ts └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | *.local 12 | 13 | # Editor directories and files 14 | .vscode/* 15 | !.vscode/extensions.json 16 | .idea 17 | .DS_Store 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw? 23 | .vercel -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Three Offscreen 2 | 3 | ThreeJS with Offscreen canvas with fallback support 4 | 5 | Adding `#regular` to the URL overrides the setting to show the regular canvas method 6 | -------------------------------------------------------------------------------- /dist/Horse.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomorrowevening/three-offscreen/785a96a2967e59f484efd97dea4e2cdd08468d2d/dist/Horse.glb -------------------------------------------------------------------------------- /dist/Idle.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomorrowevening/three-offscreen/785a96a2967e59f484efd97dea4e2cdd08468d2d/dist/Idle.fbx -------------------------------------------------------------------------------- /dist/assets/index-CjSOBxjP.css: -------------------------------------------------------------------------------- 1 | :root{font-family:Inter,system-ui,Avenir,Helvetica,Arial,sans-serif;line-height:1.5;font-weight:400;color-scheme:light dark;color:#ffffffde;background-color:#242424;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}a{font-weight:500;color:#646cff;text-decoration:inherit}a:hover{color:#535bf2}html,body{margin:0;padding:0;min-width:100%;min-height:100%;width:100%;height:100%;overflow:hidden}#root{position:absolute;left:0;right:0;top:0;bottom:0}h1{font-size:3.2em;line-height:1.1}button{border-radius:8px;border:1px solid transparent;padding:.6em 1.2em;font-size:1em;font-weight:500;font-family:inherit;background-color:#1a1a1a;cursor:pointer;position:absolute;left:50%;top:0;transform:translate(-50%)}button:hover{border-color:#646cff}button:focus,button:focus-visible{outline:4px auto -webkit-focus-ring-color}p{color:#fff;position:absolute;left:50%;top:50px;transform:translate(-50%)}@media (prefers-color-scheme: light){:root{color:#213547;background-color:#fff}a:hover{color:#747bff}button{background-color:#f9f9f9}} 2 | -------------------------------------------------------------------------------- /dist/cube/nx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomorrowevening/three-offscreen/785a96a2967e59f484efd97dea4e2cdd08468d2d/dist/cube/nx.png -------------------------------------------------------------------------------- /dist/cube/ny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomorrowevening/three-offscreen/785a96a2967e59f484efd97dea4e2cdd08468d2d/dist/cube/ny.png -------------------------------------------------------------------------------- /dist/cube/nz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomorrowevening/three-offscreen/785a96a2967e59f484efd97dea4e2cdd08468d2d/dist/cube/nz.png -------------------------------------------------------------------------------- /dist/cube/px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomorrowevening/three-offscreen/785a96a2967e59f484efd97dea4e2cdd08468d2d/dist/cube/px.png -------------------------------------------------------------------------------- /dist/cube/py.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomorrowevening/three-offscreen/785a96a2967e59f484efd97dea4e2cdd08468d2d/dist/cube/py.png -------------------------------------------------------------------------------- /dist/cube/pz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomorrowevening/three-offscreen/785a96a2967e59f484efd97dea4e2cdd08468d2d/dist/cube/pz.png -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ThreeJS Offscreen Canvas 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /dist/libs/draco/README.md: -------------------------------------------------------------------------------- 1 | # Draco 3D Data Compression 2 | 3 | Draco is an open-source library for compressing and decompressing 3D geometric meshes and point clouds. It is intended to improve the storage and transmission of 3D graphics. 4 | 5 | [Website](https://google.github.io/draco/) | [GitHub](https://github.com/google/draco) 6 | 7 | ## Contents 8 | 9 | This folder contains three utilities: 10 | 11 | * `draco_decoder.js` — Emscripten-compiled decoder, compatible with any modern browser. 12 | * `draco_decoder.wasm` — WebAssembly decoder, compatible with newer browsers and devices. 13 | * `draco_wasm_wrapper.js` — JavaScript wrapper for the WASM decoder. 14 | 15 | Each file is provided in two variations: 16 | 17 | * **Default:** Latest stable builds, tracking the project's [master branch](https://github.com/google/draco). 18 | * **glTF:** Builds targeted by the [glTF mesh compression extension](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression), tracking the [corresponding Draco branch](https://github.com/google/draco/tree/gltf_2.0_draco_extension). 19 | 20 | Either variation may be used with `THREE.DRACOLoader`: 21 | 22 | ```js 23 | var dracoLoader = new THREE.DRACOLoader(); 24 | dracoLoader.setDecoderPath('path/to/decoders/'); 25 | dracoLoader.setDecoderConfig({type: 'js'}); // (Optional) Override detection of WASM support. 26 | ``` 27 | 28 | Further [documentation on GitHub](https://github.com/google/draco/tree/master/javascript/example#static-loading-javascript-decoder). 29 | 30 | ## License 31 | 32 | [Apache License 2.0](https://github.com/google/draco/blob/master/LICENSE) 33 | -------------------------------------------------------------------------------- /dist/libs/draco/draco_decoder.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomorrowevening/three-offscreen/785a96a2967e59f484efd97dea4e2cdd08468d2d/dist/libs/draco/draco_decoder.wasm -------------------------------------------------------------------------------- /dist/libs/draco/gltf/draco_decoder.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomorrowevening/three-offscreen/785a96a2967e59f484efd97dea4e2cdd08468d2d/dist/libs/draco/gltf/draco_decoder.wasm -------------------------------------------------------------------------------- /dist/libs/draco/gltf/draco_wasm_wrapper.js: -------------------------------------------------------------------------------- 1 | var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.arrayIteratorImpl=function(h){var n=0;return function(){return n>>0,$jscomp.propertyToPolyfillSymbol[l]=$jscomp.IS_SYMBOL_NATIVE? 7 | $jscomp.global.Symbol(l):$jscomp.POLYFILL_PREFIX+k+"$"+l),$jscomp.defineProperty(p,$jscomp.propertyToPolyfillSymbol[l],{configurable:!0,writable:!0,value:n})))}; 8 | $jscomp.polyfill("Promise",function(h){function n(){this.batch_=null}function k(f){return f instanceof l?f:new l(function(q,u){q(f)})}if(h&&(!($jscomp.FORCE_POLYFILL_PROMISE||$jscomp.FORCE_POLYFILL_PROMISE_WHEN_NO_UNHANDLED_REJECTION&&"undefined"===typeof $jscomp.global.PromiseRejectionEvent)||!$jscomp.global.Promise||-1===$jscomp.global.Promise.toString().indexOf("[native code]")))return h;n.prototype.asyncExecute=function(f){if(null==this.batch_){this.batch_=[];var q=this;this.asyncExecuteFunction(function(){q.executeBatch_()})}this.batch_.push(f)}; 9 | var p=$jscomp.global.setTimeout;n.prototype.asyncExecuteFunction=function(f){p(f,0)};n.prototype.executeBatch_=function(){for(;this.batch_&&this.batch_.length;){var f=this.batch_;this.batch_=[];for(var q=0;q=y}},"es6","es3"); 19 | $jscomp.polyfill("Array.prototype.copyWithin",function(h){function n(k){k=Number(k);return Infinity===k||-Infinity===k?k:k|0}return h?h:function(k,p,l){var y=this.length;k=n(k);p=n(p);l=void 0===l?y:n(l);k=0>k?Math.max(y+k,0):Math.min(k,y);p=0>p?Math.max(y+p,0):Math.min(p,y);l=0>l?Math.max(y+l,0):Math.min(l,y);if(kp;)--l in this?this[--k]=this[l]:delete this[--k];return this}},"es6","es3"); 20 | $jscomp.typedArrayCopyWithin=function(h){return h?h:Array.prototype.copyWithin};$jscomp.polyfill("Int8Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Uint8Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Uint8ClampedArray.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Int16Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5"); 21 | $jscomp.polyfill("Uint16Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Int32Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Uint32Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Float32Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Float64Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5"); 22 | var DracoDecoderModule=function(){var h="undefined"!==typeof document&&document.currentScript?document.currentScript.src:void 0;"undefined"!==typeof __filename&&(h=h||__filename);return function(n){function k(e){return a.locateFile?a.locateFile(e,U):U+e}function p(e,b){if(e){var c=ia;var d=e+b;for(b=e;c[b]&&!(b>=d);)++b;if(16g?d+=String.fromCharCode(g):(g-=65536,d+=String.fromCharCode(55296|g>>10,56320|g&1023))}}else d+=String.fromCharCode(g)}c=d}}else c="";return c}function l(){var e=ja.buffer;a.HEAP8=W=new Int8Array(e);a.HEAP16=new Int16Array(e);a.HEAP32=ca=new Int32Array(e);a.HEAPU8=ia=new Uint8Array(e);a.HEAPU16=new Uint16Array(e);a.HEAPU32=Y=new Uint32Array(e);a.HEAPF32=new Float32Array(e);a.HEAPF64=new Float64Array(e)}function y(e){if(a.onAbort)a.onAbort(e); 24 | e="Aborted("+e+")";da(e);sa=!0;e=new WebAssembly.RuntimeError(e+". Build with -sASSERTIONS for more info.");ka(e);throw e;}function f(e){try{if(e==P&&ea)return new Uint8Array(ea);if(ma)return ma(e);throw"both async and sync fetching of the wasm failed";}catch(b){y(b)}}function q(){if(!ea&&(ta||fa)){if("function"==typeof fetch&&!P.startsWith("file://"))return fetch(P,{credentials:"same-origin"}).then(function(e){if(!e.ok)throw"failed to load wasm binary file at '"+P+"'";return e.arrayBuffer()}).catch(function(){return f(P)}); 25 | if(na)return new Promise(function(e,b){na(P,function(c){e(new Uint8Array(c))},b)})}return Promise.resolve().then(function(){return f(P)})}function u(e){for(;0>2]=b};this.get_type=function(){return Y[this.ptr+4>>2]};this.set_destructor=function(b){Y[this.ptr+8>>2]=b};this.get_destructor=function(){return Y[this.ptr+8>>2]};this.set_refcount=function(b){ca[this.ptr>>2]=b};this.set_caught=function(b){W[this.ptr+ 26 | 12>>0]=b?1:0};this.get_caught=function(){return 0!=W[this.ptr+12>>0]};this.set_rethrown=function(b){W[this.ptr+13>>0]=b?1:0};this.get_rethrown=function(){return 0!=W[this.ptr+13>>0]};this.init=function(b,c){this.set_adjusted_ptr(0);this.set_type(b);this.set_destructor(c);this.set_refcount(0);this.set_caught(!1);this.set_rethrown(!1)};this.add_ref=function(){ca[this.ptr>>2]+=1};this.release_ref=function(){var b=ca[this.ptr>>2];ca[this.ptr>>2]=b-1;return 1===b};this.set_adjusted_ptr=function(b){Y[this.ptr+ 27 | 16>>2]=b};this.get_adjusted_ptr=function(){return Y[this.ptr+16>>2]};this.get_exception_ptr=function(){if(ua(this.get_type()))return Y[this.excPtr>>2];var b=this.get_adjusted_ptr();return 0!==b?b:this.excPtr}}function F(){function e(){if(!la&&(la=!0,a.calledRun=!0,!sa)){va=!0;u(oa);wa(a);if(a.onRuntimeInitialized)a.onRuntimeInitialized();if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;)xa.unshift(a.postRun.shift());u(xa)}}if(!(0=d?b++:2047>=d?b+=2:55296<=d&&57343>= 29 | d?(b+=4,++c):b+=3}b=Array(b+1);c=0;d=b.length;if(0=t){var aa=e.charCodeAt(++g);t=65536+((t&1023)<<10)|aa&1023}if(127>=t){if(c>=d)break;b[c++]=t}else{if(2047>=t){if(c+1>=d)break;b[c++]=192|t>>6}else{if(65535>=t){if(c+2>=d)break;b[c++]=224|t>>12}else{if(c+3>=d)break;b[c++]=240|t>>18;b[c++]=128|t>>12&63}b[c++]=128|t>>6&63}b[c++]=128|t&63}}b[c]=0}e=r.alloc(b,W);r.copy(b,W,e);return e}return e}function Z(e){if("object"=== 30 | typeof e){var b=r.alloc(e,W);r.copy(e,W,b);return b}return e}function X(){throw"cannot construct a VoidPtr, no constructor in IDL";}function S(){this.ptr=za();w(S)[this.ptr]=this}function Q(){this.ptr=Aa();w(Q)[this.ptr]=this}function V(){this.ptr=Ba();w(V)[this.ptr]=this}function x(){this.ptr=Ca();w(x)[this.ptr]=this}function D(){this.ptr=Da();w(D)[this.ptr]=this}function G(){this.ptr=Ea();w(G)[this.ptr]=this}function H(){this.ptr=Fa();w(H)[this.ptr]=this}function E(){this.ptr=Ga();w(E)[this.ptr]= 31 | this}function T(){this.ptr=Ha();w(T)[this.ptr]=this}function C(){throw"cannot construct a Status, no constructor in IDL";}function I(){this.ptr=Ia();w(I)[this.ptr]=this}function J(){this.ptr=Ja();w(J)[this.ptr]=this}function K(){this.ptr=Ka();w(K)[this.ptr]=this}function L(){this.ptr=La();w(L)[this.ptr]=this}function M(){this.ptr=Ma();w(M)[this.ptr]=this}function N(){this.ptr=Na();w(N)[this.ptr]=this}function O(){this.ptr=Oa();w(O)[this.ptr]=this}function z(){this.ptr=Pa();w(z)[this.ptr]=this}function m(){this.ptr= 32 | Qa();w(m)[this.ptr]=this}n=void 0===n?{}:n;var a="undefined"!=typeof n?n:{},wa,ka;a.ready=new Promise(function(e,b){wa=e;ka=b});var Ra=!1,Sa=!1;a.onRuntimeInitialized=function(){Ra=!0;if(Sa&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.onModuleParsed=function(){Sa=!0;if(Ra&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.isVersionSupported=function(e){if("string"!==typeof e)return!1;e=e.split(".");return 2>e.length||3=e[1]?!0:0!=e[0]||10< 33 | e[1]?!1:!0};var Ta=Object.assign({},a),ta="object"==typeof window,fa="function"==typeof importScripts,Ua="object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node,U="";if(Ua){var Va=require("fs"),pa=require("path");U=fa?pa.dirname(U)+"/":__dirname+"/";var Wa=function(e,b){e=e.startsWith("file://")?new URL(e):pa.normalize(e);return Va.readFileSync(e,b?void 0:"utf8")};var ma=function(e){e=Wa(e,!0);e.buffer||(e=new Uint8Array(e));return e};var na=function(e, 34 | b,c){e=e.startsWith("file://")?new URL(e):pa.normalize(e);Va.readFile(e,function(d,g){d?c(d):b(g.buffer)})};1>>=0;if(2147483648=c;c*=2){var d=b*(1+.2/c);d=Math.min(d,e+100663296);var g=Math;d=Math.max(e,d);g=g.min.call(g,2147483648,d+(65536-d%65536)%65536);a:{d=ja.buffer;try{ja.grow(g-d.byteLength+65535>>>16);l();var t=1;break a}catch(aa){}t=void 0}if(t)return!0}return!1}};(function(){function e(g,t){a.asm=g.exports;ja=a.asm.e;l();oa.unshift(a.asm.f);ba--;a.monitorRunDependencies&&a.monitorRunDependencies(ba);0==ba&&(null!==qa&&(clearInterval(qa),qa=null),ha&&(g=ha,ha=null,g()))}function b(g){e(g.instance)} 38 | function c(g){return q().then(function(t){return WebAssembly.instantiate(t,d)}).then(function(t){return t}).then(g,function(t){da("failed to asynchronously prepare wasm: "+t);y(t)})}var d={a:qd};ba++;a.monitorRunDependencies&&a.monitorRunDependencies(ba);if(a.instantiateWasm)try{return a.instantiateWasm(d,e)}catch(g){da("Module.instantiateWasm callback failed with error: "+g),ka(g)}(function(){return ea||"function"!=typeof WebAssembly.instantiateStreaming||P.startsWith("data:application/octet-stream;base64,")|| 39 | P.startsWith("file://")||Ua||"function"!=typeof fetch?c(b):fetch(P,{credentials:"same-origin"}).then(function(g){return WebAssembly.instantiateStreaming(g,d).then(b,function(t){da("wasm streaming compile failed: "+t);da("falling back to ArrayBuffer instantiation");return c(b)})})})().catch(ka);return{}})();var Xa=a._emscripten_bind_VoidPtr___destroy___0=function(){return(Xa=a._emscripten_bind_VoidPtr___destroy___0=a.asm.h).apply(null,arguments)},za=a._emscripten_bind_DecoderBuffer_DecoderBuffer_0= 40 | function(){return(za=a._emscripten_bind_DecoderBuffer_DecoderBuffer_0=a.asm.i).apply(null,arguments)},Ya=a._emscripten_bind_DecoderBuffer_Init_2=function(){return(Ya=a._emscripten_bind_DecoderBuffer_Init_2=a.asm.j).apply(null,arguments)},Za=a._emscripten_bind_DecoderBuffer___destroy___0=function(){return(Za=a._emscripten_bind_DecoderBuffer___destroy___0=a.asm.k).apply(null,arguments)},Aa=a._emscripten_bind_AttributeTransformData_AttributeTransformData_0=function(){return(Aa=a._emscripten_bind_AttributeTransformData_AttributeTransformData_0= 41 | a.asm.l).apply(null,arguments)},$a=a._emscripten_bind_AttributeTransformData_transform_type_0=function(){return($a=a._emscripten_bind_AttributeTransformData_transform_type_0=a.asm.m).apply(null,arguments)},ab=a._emscripten_bind_AttributeTransformData___destroy___0=function(){return(ab=a._emscripten_bind_AttributeTransformData___destroy___0=a.asm.n).apply(null,arguments)},Ba=a._emscripten_bind_GeometryAttribute_GeometryAttribute_0=function(){return(Ba=a._emscripten_bind_GeometryAttribute_GeometryAttribute_0= 42 | a.asm.o).apply(null,arguments)},bb=a._emscripten_bind_GeometryAttribute___destroy___0=function(){return(bb=a._emscripten_bind_GeometryAttribute___destroy___0=a.asm.p).apply(null,arguments)},Ca=a._emscripten_bind_PointAttribute_PointAttribute_0=function(){return(Ca=a._emscripten_bind_PointAttribute_PointAttribute_0=a.asm.q).apply(null,arguments)},cb=a._emscripten_bind_PointAttribute_size_0=function(){return(cb=a._emscripten_bind_PointAttribute_size_0=a.asm.r).apply(null,arguments)},db=a._emscripten_bind_PointAttribute_GetAttributeTransformData_0= 43 | function(){return(db=a._emscripten_bind_PointAttribute_GetAttributeTransformData_0=a.asm.s).apply(null,arguments)},eb=a._emscripten_bind_PointAttribute_attribute_type_0=function(){return(eb=a._emscripten_bind_PointAttribute_attribute_type_0=a.asm.t).apply(null,arguments)},fb=a._emscripten_bind_PointAttribute_data_type_0=function(){return(fb=a._emscripten_bind_PointAttribute_data_type_0=a.asm.u).apply(null,arguments)},gb=a._emscripten_bind_PointAttribute_num_components_0=function(){return(gb=a._emscripten_bind_PointAttribute_num_components_0= 44 | a.asm.v).apply(null,arguments)},hb=a._emscripten_bind_PointAttribute_normalized_0=function(){return(hb=a._emscripten_bind_PointAttribute_normalized_0=a.asm.w).apply(null,arguments)},ib=a._emscripten_bind_PointAttribute_byte_stride_0=function(){return(ib=a._emscripten_bind_PointAttribute_byte_stride_0=a.asm.x).apply(null,arguments)},jb=a._emscripten_bind_PointAttribute_byte_offset_0=function(){return(jb=a._emscripten_bind_PointAttribute_byte_offset_0=a.asm.y).apply(null,arguments)},kb=a._emscripten_bind_PointAttribute_unique_id_0= 45 | function(){return(kb=a._emscripten_bind_PointAttribute_unique_id_0=a.asm.z).apply(null,arguments)},lb=a._emscripten_bind_PointAttribute___destroy___0=function(){return(lb=a._emscripten_bind_PointAttribute___destroy___0=a.asm.A).apply(null,arguments)},Da=a._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0=function(){return(Da=a._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0=a.asm.B).apply(null,arguments)},mb=a._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1= 46 | function(){return(mb=a._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1=a.asm.C).apply(null,arguments)},nb=a._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0=function(){return(nb=a._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0=a.asm.D).apply(null,arguments)},ob=a._emscripten_bind_AttributeQuantizationTransform_min_value_1=function(){return(ob=a._emscripten_bind_AttributeQuantizationTransform_min_value_1=a.asm.E).apply(null,arguments)},pb= 47 | a._emscripten_bind_AttributeQuantizationTransform_range_0=function(){return(pb=a._emscripten_bind_AttributeQuantizationTransform_range_0=a.asm.F).apply(null,arguments)},qb=a._emscripten_bind_AttributeQuantizationTransform___destroy___0=function(){return(qb=a._emscripten_bind_AttributeQuantizationTransform___destroy___0=a.asm.G).apply(null,arguments)},Ea=a._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0=function(){return(Ea=a._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0= 48 | a.asm.H).apply(null,arguments)},rb=a._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1=function(){return(rb=a._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1=a.asm.I).apply(null,arguments)},sb=a._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0=function(){return(sb=a._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0=a.asm.J).apply(null,arguments)},tb=a._emscripten_bind_AttributeOctahedronTransform___destroy___0=function(){return(tb= 49 | a._emscripten_bind_AttributeOctahedronTransform___destroy___0=a.asm.K).apply(null,arguments)},Fa=a._emscripten_bind_PointCloud_PointCloud_0=function(){return(Fa=a._emscripten_bind_PointCloud_PointCloud_0=a.asm.L).apply(null,arguments)},ub=a._emscripten_bind_PointCloud_num_attributes_0=function(){return(ub=a._emscripten_bind_PointCloud_num_attributes_0=a.asm.M).apply(null,arguments)},vb=a._emscripten_bind_PointCloud_num_points_0=function(){return(vb=a._emscripten_bind_PointCloud_num_points_0=a.asm.N).apply(null, 50 | arguments)},wb=a._emscripten_bind_PointCloud___destroy___0=function(){return(wb=a._emscripten_bind_PointCloud___destroy___0=a.asm.O).apply(null,arguments)},Ga=a._emscripten_bind_Mesh_Mesh_0=function(){return(Ga=a._emscripten_bind_Mesh_Mesh_0=a.asm.P).apply(null,arguments)},xb=a._emscripten_bind_Mesh_num_faces_0=function(){return(xb=a._emscripten_bind_Mesh_num_faces_0=a.asm.Q).apply(null,arguments)},yb=a._emscripten_bind_Mesh_num_attributes_0=function(){return(yb=a._emscripten_bind_Mesh_num_attributes_0= 51 | a.asm.R).apply(null,arguments)},zb=a._emscripten_bind_Mesh_num_points_0=function(){return(zb=a._emscripten_bind_Mesh_num_points_0=a.asm.S).apply(null,arguments)},Ab=a._emscripten_bind_Mesh___destroy___0=function(){return(Ab=a._emscripten_bind_Mesh___destroy___0=a.asm.T).apply(null,arguments)},Ha=a._emscripten_bind_Metadata_Metadata_0=function(){return(Ha=a._emscripten_bind_Metadata_Metadata_0=a.asm.U).apply(null,arguments)},Bb=a._emscripten_bind_Metadata___destroy___0=function(){return(Bb=a._emscripten_bind_Metadata___destroy___0= 52 | a.asm.V).apply(null,arguments)},Cb=a._emscripten_bind_Status_code_0=function(){return(Cb=a._emscripten_bind_Status_code_0=a.asm.W).apply(null,arguments)},Db=a._emscripten_bind_Status_ok_0=function(){return(Db=a._emscripten_bind_Status_ok_0=a.asm.X).apply(null,arguments)},Eb=a._emscripten_bind_Status_error_msg_0=function(){return(Eb=a._emscripten_bind_Status_error_msg_0=a.asm.Y).apply(null,arguments)},Fb=a._emscripten_bind_Status___destroy___0=function(){return(Fb=a._emscripten_bind_Status___destroy___0= 53 | a.asm.Z).apply(null,arguments)},Ia=a._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0=function(){return(Ia=a._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0=a.asm._).apply(null,arguments)},Gb=a._emscripten_bind_DracoFloat32Array_GetValue_1=function(){return(Gb=a._emscripten_bind_DracoFloat32Array_GetValue_1=a.asm.$).apply(null,arguments)},Hb=a._emscripten_bind_DracoFloat32Array_size_0=function(){return(Hb=a._emscripten_bind_DracoFloat32Array_size_0=a.asm.aa).apply(null,arguments)},Ib= 54 | a._emscripten_bind_DracoFloat32Array___destroy___0=function(){return(Ib=a._emscripten_bind_DracoFloat32Array___destroy___0=a.asm.ba).apply(null,arguments)},Ja=a._emscripten_bind_DracoInt8Array_DracoInt8Array_0=function(){return(Ja=a._emscripten_bind_DracoInt8Array_DracoInt8Array_0=a.asm.ca).apply(null,arguments)},Jb=a._emscripten_bind_DracoInt8Array_GetValue_1=function(){return(Jb=a._emscripten_bind_DracoInt8Array_GetValue_1=a.asm.da).apply(null,arguments)},Kb=a._emscripten_bind_DracoInt8Array_size_0= 55 | function(){return(Kb=a._emscripten_bind_DracoInt8Array_size_0=a.asm.ea).apply(null,arguments)},Lb=a._emscripten_bind_DracoInt8Array___destroy___0=function(){return(Lb=a._emscripten_bind_DracoInt8Array___destroy___0=a.asm.fa).apply(null,arguments)},Ka=a._emscripten_bind_DracoUInt8Array_DracoUInt8Array_0=function(){return(Ka=a._emscripten_bind_DracoUInt8Array_DracoUInt8Array_0=a.asm.ga).apply(null,arguments)},Mb=a._emscripten_bind_DracoUInt8Array_GetValue_1=function(){return(Mb=a._emscripten_bind_DracoUInt8Array_GetValue_1= 56 | a.asm.ha).apply(null,arguments)},Nb=a._emscripten_bind_DracoUInt8Array_size_0=function(){return(Nb=a._emscripten_bind_DracoUInt8Array_size_0=a.asm.ia).apply(null,arguments)},Ob=a._emscripten_bind_DracoUInt8Array___destroy___0=function(){return(Ob=a._emscripten_bind_DracoUInt8Array___destroy___0=a.asm.ja).apply(null,arguments)},La=a._emscripten_bind_DracoInt16Array_DracoInt16Array_0=function(){return(La=a._emscripten_bind_DracoInt16Array_DracoInt16Array_0=a.asm.ka).apply(null,arguments)},Pb=a._emscripten_bind_DracoInt16Array_GetValue_1= 57 | function(){return(Pb=a._emscripten_bind_DracoInt16Array_GetValue_1=a.asm.la).apply(null,arguments)},Qb=a._emscripten_bind_DracoInt16Array_size_0=function(){return(Qb=a._emscripten_bind_DracoInt16Array_size_0=a.asm.ma).apply(null,arguments)},Rb=a._emscripten_bind_DracoInt16Array___destroy___0=function(){return(Rb=a._emscripten_bind_DracoInt16Array___destroy___0=a.asm.na).apply(null,arguments)},Ma=a._emscripten_bind_DracoUInt16Array_DracoUInt16Array_0=function(){return(Ma=a._emscripten_bind_DracoUInt16Array_DracoUInt16Array_0= 58 | a.asm.oa).apply(null,arguments)},Sb=a._emscripten_bind_DracoUInt16Array_GetValue_1=function(){return(Sb=a._emscripten_bind_DracoUInt16Array_GetValue_1=a.asm.pa).apply(null,arguments)},Tb=a._emscripten_bind_DracoUInt16Array_size_0=function(){return(Tb=a._emscripten_bind_DracoUInt16Array_size_0=a.asm.qa).apply(null,arguments)},Ub=a._emscripten_bind_DracoUInt16Array___destroy___0=function(){return(Ub=a._emscripten_bind_DracoUInt16Array___destroy___0=a.asm.ra).apply(null,arguments)},Na=a._emscripten_bind_DracoInt32Array_DracoInt32Array_0= 59 | function(){return(Na=a._emscripten_bind_DracoInt32Array_DracoInt32Array_0=a.asm.sa).apply(null,arguments)},Vb=a._emscripten_bind_DracoInt32Array_GetValue_1=function(){return(Vb=a._emscripten_bind_DracoInt32Array_GetValue_1=a.asm.ta).apply(null,arguments)},Wb=a._emscripten_bind_DracoInt32Array_size_0=function(){return(Wb=a._emscripten_bind_DracoInt32Array_size_0=a.asm.ua).apply(null,arguments)},Xb=a._emscripten_bind_DracoInt32Array___destroy___0=function(){return(Xb=a._emscripten_bind_DracoInt32Array___destroy___0= 60 | a.asm.va).apply(null,arguments)},Oa=a._emscripten_bind_DracoUInt32Array_DracoUInt32Array_0=function(){return(Oa=a._emscripten_bind_DracoUInt32Array_DracoUInt32Array_0=a.asm.wa).apply(null,arguments)},Yb=a._emscripten_bind_DracoUInt32Array_GetValue_1=function(){return(Yb=a._emscripten_bind_DracoUInt32Array_GetValue_1=a.asm.xa).apply(null,arguments)},Zb=a._emscripten_bind_DracoUInt32Array_size_0=function(){return(Zb=a._emscripten_bind_DracoUInt32Array_size_0=a.asm.ya).apply(null,arguments)},$b=a._emscripten_bind_DracoUInt32Array___destroy___0= 61 | function(){return($b=a._emscripten_bind_DracoUInt32Array___destroy___0=a.asm.za).apply(null,arguments)},Pa=a._emscripten_bind_MetadataQuerier_MetadataQuerier_0=function(){return(Pa=a._emscripten_bind_MetadataQuerier_MetadataQuerier_0=a.asm.Aa).apply(null,arguments)},ac=a._emscripten_bind_MetadataQuerier_HasEntry_2=function(){return(ac=a._emscripten_bind_MetadataQuerier_HasEntry_2=a.asm.Ba).apply(null,arguments)},bc=a._emscripten_bind_MetadataQuerier_GetIntEntry_2=function(){return(bc=a._emscripten_bind_MetadataQuerier_GetIntEntry_2= 62 | a.asm.Ca).apply(null,arguments)},cc=a._emscripten_bind_MetadataQuerier_GetIntEntryArray_3=function(){return(cc=a._emscripten_bind_MetadataQuerier_GetIntEntryArray_3=a.asm.Da).apply(null,arguments)},dc=a._emscripten_bind_MetadataQuerier_GetDoubleEntry_2=function(){return(dc=a._emscripten_bind_MetadataQuerier_GetDoubleEntry_2=a.asm.Ea).apply(null,arguments)},ec=a._emscripten_bind_MetadataQuerier_GetStringEntry_2=function(){return(ec=a._emscripten_bind_MetadataQuerier_GetStringEntry_2=a.asm.Fa).apply(null, 63 | arguments)},fc=a._emscripten_bind_MetadataQuerier_NumEntries_1=function(){return(fc=a._emscripten_bind_MetadataQuerier_NumEntries_1=a.asm.Ga).apply(null,arguments)},gc=a._emscripten_bind_MetadataQuerier_GetEntryName_2=function(){return(gc=a._emscripten_bind_MetadataQuerier_GetEntryName_2=a.asm.Ha).apply(null,arguments)},hc=a._emscripten_bind_MetadataQuerier___destroy___0=function(){return(hc=a._emscripten_bind_MetadataQuerier___destroy___0=a.asm.Ia).apply(null,arguments)},Qa=a._emscripten_bind_Decoder_Decoder_0= 64 | function(){return(Qa=a._emscripten_bind_Decoder_Decoder_0=a.asm.Ja).apply(null,arguments)},ic=a._emscripten_bind_Decoder_DecodeArrayToPointCloud_3=function(){return(ic=a._emscripten_bind_Decoder_DecodeArrayToPointCloud_3=a.asm.Ka).apply(null,arguments)},jc=a._emscripten_bind_Decoder_DecodeArrayToMesh_3=function(){return(jc=a._emscripten_bind_Decoder_DecodeArrayToMesh_3=a.asm.La).apply(null,arguments)},kc=a._emscripten_bind_Decoder_GetAttributeId_2=function(){return(kc=a._emscripten_bind_Decoder_GetAttributeId_2= 65 | a.asm.Ma).apply(null,arguments)},lc=a._emscripten_bind_Decoder_GetAttributeIdByName_2=function(){return(lc=a._emscripten_bind_Decoder_GetAttributeIdByName_2=a.asm.Na).apply(null,arguments)},mc=a._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3=function(){return(mc=a._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3=a.asm.Oa).apply(null,arguments)},nc=a._emscripten_bind_Decoder_GetAttribute_2=function(){return(nc=a._emscripten_bind_Decoder_GetAttribute_2=a.asm.Pa).apply(null,arguments)}, 66 | oc=a._emscripten_bind_Decoder_GetAttributeByUniqueId_2=function(){return(oc=a._emscripten_bind_Decoder_GetAttributeByUniqueId_2=a.asm.Qa).apply(null,arguments)},pc=a._emscripten_bind_Decoder_GetMetadata_1=function(){return(pc=a._emscripten_bind_Decoder_GetMetadata_1=a.asm.Ra).apply(null,arguments)},qc=a._emscripten_bind_Decoder_GetAttributeMetadata_2=function(){return(qc=a._emscripten_bind_Decoder_GetAttributeMetadata_2=a.asm.Sa).apply(null,arguments)},rc=a._emscripten_bind_Decoder_GetFaceFromMesh_3= 67 | function(){return(rc=a._emscripten_bind_Decoder_GetFaceFromMesh_3=a.asm.Ta).apply(null,arguments)},sc=a._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2=function(){return(sc=a._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2=a.asm.Ua).apply(null,arguments)},tc=a._emscripten_bind_Decoder_GetTrianglesUInt16Array_3=function(){return(tc=a._emscripten_bind_Decoder_GetTrianglesUInt16Array_3=a.asm.Va).apply(null,arguments)},uc=a._emscripten_bind_Decoder_GetTrianglesUInt32Array_3=function(){return(uc= 68 | a._emscripten_bind_Decoder_GetTrianglesUInt32Array_3=a.asm.Wa).apply(null,arguments)},vc=a._emscripten_bind_Decoder_GetAttributeFloat_3=function(){return(vc=a._emscripten_bind_Decoder_GetAttributeFloat_3=a.asm.Xa).apply(null,arguments)},wc=a._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3=function(){return(wc=a._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3=a.asm.Ya).apply(null,arguments)},xc=a._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3=function(){return(xc=a._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3= 69 | a.asm.Za).apply(null,arguments)},yc=a._emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3=function(){return(yc=a._emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3=a.asm._a).apply(null,arguments)},zc=a._emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3=function(){return(zc=a._emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3=a.asm.$a).apply(null,arguments)},Ac=a._emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3=function(){return(Ac=a._emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3= 70 | a.asm.ab).apply(null,arguments)},Bc=a._emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3=function(){return(Bc=a._emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3=a.asm.bb).apply(null,arguments)},Cc=a._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3=function(){return(Cc=a._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3=a.asm.cb).apply(null,arguments)},Dc=a._emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3=function(){return(Dc=a._emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3= 71 | a.asm.db).apply(null,arguments)},Ec=a._emscripten_bind_Decoder_GetAttributeDataArrayForAllPoints_5=function(){return(Ec=a._emscripten_bind_Decoder_GetAttributeDataArrayForAllPoints_5=a.asm.eb).apply(null,arguments)},Fc=a._emscripten_bind_Decoder_SkipAttributeTransform_1=function(){return(Fc=a._emscripten_bind_Decoder_SkipAttributeTransform_1=a.asm.fb).apply(null,arguments)},Gc=a._emscripten_bind_Decoder_GetEncodedGeometryType_Deprecated_1=function(){return(Gc=a._emscripten_bind_Decoder_GetEncodedGeometryType_Deprecated_1= 72 | a.asm.gb).apply(null,arguments)},Hc=a._emscripten_bind_Decoder_DecodeBufferToPointCloud_2=function(){return(Hc=a._emscripten_bind_Decoder_DecodeBufferToPointCloud_2=a.asm.hb).apply(null,arguments)},Ic=a._emscripten_bind_Decoder_DecodeBufferToMesh_2=function(){return(Ic=a._emscripten_bind_Decoder_DecodeBufferToMesh_2=a.asm.ib).apply(null,arguments)},Jc=a._emscripten_bind_Decoder___destroy___0=function(){return(Jc=a._emscripten_bind_Decoder___destroy___0=a.asm.jb).apply(null,arguments)},Kc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM= 73 | function(){return(Kc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM=a.asm.kb).apply(null,arguments)},Lc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM=function(){return(Lc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM=a.asm.lb).apply(null,arguments)},Mc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM=function(){return(Mc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM= 74 | a.asm.mb).apply(null,arguments)},Nc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM=function(){return(Nc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM=a.asm.nb).apply(null,arguments)},Oc=a._emscripten_enum_draco_GeometryAttribute_Type_INVALID=function(){return(Oc=a._emscripten_enum_draco_GeometryAttribute_Type_INVALID=a.asm.ob).apply(null,arguments)},Pc=a._emscripten_enum_draco_GeometryAttribute_Type_POSITION=function(){return(Pc=a._emscripten_enum_draco_GeometryAttribute_Type_POSITION= 75 | a.asm.pb).apply(null,arguments)},Qc=a._emscripten_enum_draco_GeometryAttribute_Type_NORMAL=function(){return(Qc=a._emscripten_enum_draco_GeometryAttribute_Type_NORMAL=a.asm.qb).apply(null,arguments)},Rc=a._emscripten_enum_draco_GeometryAttribute_Type_COLOR=function(){return(Rc=a._emscripten_enum_draco_GeometryAttribute_Type_COLOR=a.asm.rb).apply(null,arguments)},Sc=a._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD=function(){return(Sc=a._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD= 76 | a.asm.sb).apply(null,arguments)},Tc=a._emscripten_enum_draco_GeometryAttribute_Type_GENERIC=function(){return(Tc=a._emscripten_enum_draco_GeometryAttribute_Type_GENERIC=a.asm.tb).apply(null,arguments)},Uc=a._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE=function(){return(Uc=a._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE=a.asm.ub).apply(null,arguments)},Vc=a._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD=function(){return(Vc=a._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD= 77 | a.asm.vb).apply(null,arguments)},Wc=a._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH=function(){return(Wc=a._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH=a.asm.wb).apply(null,arguments)},Xc=a._emscripten_enum_draco_DataType_DT_INVALID=function(){return(Xc=a._emscripten_enum_draco_DataType_DT_INVALID=a.asm.xb).apply(null,arguments)},Yc=a._emscripten_enum_draco_DataType_DT_INT8=function(){return(Yc=a._emscripten_enum_draco_DataType_DT_INT8=a.asm.yb).apply(null,arguments)},Zc= 78 | a._emscripten_enum_draco_DataType_DT_UINT8=function(){return(Zc=a._emscripten_enum_draco_DataType_DT_UINT8=a.asm.zb).apply(null,arguments)},$c=a._emscripten_enum_draco_DataType_DT_INT16=function(){return($c=a._emscripten_enum_draco_DataType_DT_INT16=a.asm.Ab).apply(null,arguments)},ad=a._emscripten_enum_draco_DataType_DT_UINT16=function(){return(ad=a._emscripten_enum_draco_DataType_DT_UINT16=a.asm.Bb).apply(null,arguments)},bd=a._emscripten_enum_draco_DataType_DT_INT32=function(){return(bd=a._emscripten_enum_draco_DataType_DT_INT32= 79 | a.asm.Cb).apply(null,arguments)},cd=a._emscripten_enum_draco_DataType_DT_UINT32=function(){return(cd=a._emscripten_enum_draco_DataType_DT_UINT32=a.asm.Db).apply(null,arguments)},dd=a._emscripten_enum_draco_DataType_DT_INT64=function(){return(dd=a._emscripten_enum_draco_DataType_DT_INT64=a.asm.Eb).apply(null,arguments)},ed=a._emscripten_enum_draco_DataType_DT_UINT64=function(){return(ed=a._emscripten_enum_draco_DataType_DT_UINT64=a.asm.Fb).apply(null,arguments)},fd=a._emscripten_enum_draco_DataType_DT_FLOAT32= 80 | function(){return(fd=a._emscripten_enum_draco_DataType_DT_FLOAT32=a.asm.Gb).apply(null,arguments)},gd=a._emscripten_enum_draco_DataType_DT_FLOAT64=function(){return(gd=a._emscripten_enum_draco_DataType_DT_FLOAT64=a.asm.Hb).apply(null,arguments)},hd=a._emscripten_enum_draco_DataType_DT_BOOL=function(){return(hd=a._emscripten_enum_draco_DataType_DT_BOOL=a.asm.Ib).apply(null,arguments)},id=a._emscripten_enum_draco_DataType_DT_TYPES_COUNT=function(){return(id=a._emscripten_enum_draco_DataType_DT_TYPES_COUNT= 81 | a.asm.Jb).apply(null,arguments)},jd=a._emscripten_enum_draco_StatusCode_OK=function(){return(jd=a._emscripten_enum_draco_StatusCode_OK=a.asm.Kb).apply(null,arguments)},kd=a._emscripten_enum_draco_StatusCode_DRACO_ERROR=function(){return(kd=a._emscripten_enum_draco_StatusCode_DRACO_ERROR=a.asm.Lb).apply(null,arguments)},ld=a._emscripten_enum_draco_StatusCode_IO_ERROR=function(){return(ld=a._emscripten_enum_draco_StatusCode_IO_ERROR=a.asm.Mb).apply(null,arguments)},md=a._emscripten_enum_draco_StatusCode_INVALID_PARAMETER= 82 | function(){return(md=a._emscripten_enum_draco_StatusCode_INVALID_PARAMETER=a.asm.Nb).apply(null,arguments)},nd=a._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION=function(){return(nd=a._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION=a.asm.Ob).apply(null,arguments)},od=a._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION=function(){return(od=a._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION=a.asm.Pb).apply(null,arguments)};a._malloc=function(){return(a._malloc=a.asm.Qb).apply(null,arguments)}; 83 | a._free=function(){return(a._free=a.asm.Rb).apply(null,arguments)};var ua=function(){return(ua=a.asm.Sb).apply(null,arguments)};a.___start_em_js=11660;a.___stop_em_js=11758;var la;ha=function b(){la||F();la||(ha=b)};if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0=r.size?(0>>=0;switch(c.BYTES_PER_ELEMENT){case 2:d>>>=1;break;case 4:d>>>=2;break;case 8:d>>>=3}for(var g=0;gb.byteLength)return a.INVALID_GEOMETRY_TYPE;switch(b[7]){case 0:return a.POINT_CLOUD;case 1:return a.TRIANGULAR_MESH;default:return a.INVALID_GEOMETRY_TYPE}};return n.ready}}();"object"===typeof exports&&"object"===typeof module?module.exports=DracoDecoderModule:"function"===typeof define&&define.amd?define([],function(){return DracoDecoderModule}):"object"===typeof exports&&(exports.DracoDecoderModule=DracoDecoderModule); 117 | -------------------------------------------------------------------------------- /dist/uvGrid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomorrowevening/three-offscreen/785a96a2967e59f484efd97dea4e2cdd08468d2d/dist/uvGrid.jpg -------------------------------------------------------------------------------- /dist/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js' 2 | import globals from 'globals' 3 | import reactHooks from 'eslint-plugin-react-hooks' 4 | import reactRefresh from 'eslint-plugin-react-refresh' 5 | import tseslint from 'typescript-eslint' 6 | 7 | export default tseslint.config( 8 | { ignores: ['dist'] }, 9 | { 10 | extends: [js.configs.recommended, ...tseslint.configs.recommended], 11 | files: ['**/*.{ts,tsx}'], 12 | languageOptions: { 13 | ecmaVersion: 2020, 14 | globals: globals.browser, 15 | }, 16 | plugins: { 17 | 'react-hooks': reactHooks, 18 | 'react-refresh': reactRefresh, 19 | }, 20 | rules: { 21 | ...reactHooks.configs.recommended.rules, 22 | "@typescript-eslint/no-explicit-any": "off", 23 | "@typescript-eslint/no-unused-vars": "off", 24 | "@typescript-eslint/ban-ts-comment": "off", 25 | 'react-refresh/only-export-components': [ 26 | 'warn', 27 | { allowConstantExport: true }, 28 | ], 29 | }, 30 | }, 31 | ) 32 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ThreeJS Offscreen Canvas 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "offscreen-canvas", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc -b && vite build", 9 | "lint": "eslint .", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "detect-gpu": "^5.0.57", 14 | "postprocessing": "^6.36.4", 15 | "react": "^18.3.1", 16 | "react-dom": "^18.3.1", 17 | "stats-gl": "^3.6.0", 18 | "three": "^0.170.0" 19 | }, 20 | "devDependencies": { 21 | "@eslint/js": "^9.13.0", 22 | "@types/react": "^18.3.12", 23 | "@types/react-dom": "^18.3.1", 24 | "@types/three": "^0.170.0", 25 | "@vitejs/plugin-react": "^4.3.3", 26 | "eslint": "^9.13.0", 27 | "eslint-plugin-react-hooks": "^5.0.0", 28 | "eslint-plugin-react-refresh": "^0.4.14", 29 | "globals": "^15.11.0", 30 | "typescript": "~5.6.2", 31 | "typescript-eslint": "^8.11.0", 32 | "vite": "^5.4.10" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /public/Horse.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomorrowevening/three-offscreen/785a96a2967e59f484efd97dea4e2cdd08468d2d/public/Horse.glb -------------------------------------------------------------------------------- /public/Idle.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomorrowevening/three-offscreen/785a96a2967e59f484efd97dea4e2cdd08468d2d/public/Idle.fbx -------------------------------------------------------------------------------- /public/cube/nx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomorrowevening/three-offscreen/785a96a2967e59f484efd97dea4e2cdd08468d2d/public/cube/nx.png -------------------------------------------------------------------------------- /public/cube/ny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomorrowevening/three-offscreen/785a96a2967e59f484efd97dea4e2cdd08468d2d/public/cube/ny.png -------------------------------------------------------------------------------- /public/cube/nz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomorrowevening/three-offscreen/785a96a2967e59f484efd97dea4e2cdd08468d2d/public/cube/nz.png -------------------------------------------------------------------------------- /public/cube/px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomorrowevening/three-offscreen/785a96a2967e59f484efd97dea4e2cdd08468d2d/public/cube/px.png -------------------------------------------------------------------------------- /public/cube/py.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomorrowevening/three-offscreen/785a96a2967e59f484efd97dea4e2cdd08468d2d/public/cube/py.png -------------------------------------------------------------------------------- /public/cube/pz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomorrowevening/three-offscreen/785a96a2967e59f484efd97dea4e2cdd08468d2d/public/cube/pz.png -------------------------------------------------------------------------------- /public/libs/draco/README.md: -------------------------------------------------------------------------------- 1 | # Draco 3D Data Compression 2 | 3 | Draco is an open-source library for compressing and decompressing 3D geometric meshes and point clouds. It is intended to improve the storage and transmission of 3D graphics. 4 | 5 | [Website](https://google.github.io/draco/) | [GitHub](https://github.com/google/draco) 6 | 7 | ## Contents 8 | 9 | This folder contains three utilities: 10 | 11 | * `draco_decoder.js` — Emscripten-compiled decoder, compatible with any modern browser. 12 | * `draco_decoder.wasm` — WebAssembly decoder, compatible with newer browsers and devices. 13 | * `draco_wasm_wrapper.js` — JavaScript wrapper for the WASM decoder. 14 | 15 | Each file is provided in two variations: 16 | 17 | * **Default:** Latest stable builds, tracking the project's [master branch](https://github.com/google/draco). 18 | * **glTF:** Builds targeted by the [glTF mesh compression extension](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression), tracking the [corresponding Draco branch](https://github.com/google/draco/tree/gltf_2.0_draco_extension). 19 | 20 | Either variation may be used with `THREE.DRACOLoader`: 21 | 22 | ```js 23 | var dracoLoader = new THREE.DRACOLoader(); 24 | dracoLoader.setDecoderPath('path/to/decoders/'); 25 | dracoLoader.setDecoderConfig({type: 'js'}); // (Optional) Override detection of WASM support. 26 | ``` 27 | 28 | Further [documentation on GitHub](https://github.com/google/draco/tree/master/javascript/example#static-loading-javascript-decoder). 29 | 30 | ## License 31 | 32 | [Apache License 2.0](https://github.com/google/draco/blob/master/LICENSE) 33 | -------------------------------------------------------------------------------- /public/libs/draco/draco_decoder.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomorrowevening/three-offscreen/785a96a2967e59f484efd97dea4e2cdd08468d2d/public/libs/draco/draco_decoder.wasm -------------------------------------------------------------------------------- /public/libs/draco/gltf/draco_decoder.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomorrowevening/three-offscreen/785a96a2967e59f484efd97dea4e2cdd08468d2d/public/libs/draco/gltf/draco_decoder.wasm -------------------------------------------------------------------------------- /public/libs/draco/gltf/draco_wasm_wrapper.js: -------------------------------------------------------------------------------- 1 | var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.arrayIteratorImpl=function(h){var n=0;return function(){return n>>0,$jscomp.propertyToPolyfillSymbol[l]=$jscomp.IS_SYMBOL_NATIVE? 7 | $jscomp.global.Symbol(l):$jscomp.POLYFILL_PREFIX+k+"$"+l),$jscomp.defineProperty(p,$jscomp.propertyToPolyfillSymbol[l],{configurable:!0,writable:!0,value:n})))}; 8 | $jscomp.polyfill("Promise",function(h){function n(){this.batch_=null}function k(f){return f instanceof l?f:new l(function(q,u){q(f)})}if(h&&(!($jscomp.FORCE_POLYFILL_PROMISE||$jscomp.FORCE_POLYFILL_PROMISE_WHEN_NO_UNHANDLED_REJECTION&&"undefined"===typeof $jscomp.global.PromiseRejectionEvent)||!$jscomp.global.Promise||-1===$jscomp.global.Promise.toString().indexOf("[native code]")))return h;n.prototype.asyncExecute=function(f){if(null==this.batch_){this.batch_=[];var q=this;this.asyncExecuteFunction(function(){q.executeBatch_()})}this.batch_.push(f)}; 9 | var p=$jscomp.global.setTimeout;n.prototype.asyncExecuteFunction=function(f){p(f,0)};n.prototype.executeBatch_=function(){for(;this.batch_&&this.batch_.length;){var f=this.batch_;this.batch_=[];for(var q=0;q=y}},"es6","es3"); 19 | $jscomp.polyfill("Array.prototype.copyWithin",function(h){function n(k){k=Number(k);return Infinity===k||-Infinity===k?k:k|0}return h?h:function(k,p,l){var y=this.length;k=n(k);p=n(p);l=void 0===l?y:n(l);k=0>k?Math.max(y+k,0):Math.min(k,y);p=0>p?Math.max(y+p,0):Math.min(p,y);l=0>l?Math.max(y+l,0):Math.min(l,y);if(kp;)--l in this?this[--k]=this[l]:delete this[--k];return this}},"es6","es3"); 20 | $jscomp.typedArrayCopyWithin=function(h){return h?h:Array.prototype.copyWithin};$jscomp.polyfill("Int8Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Uint8Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Uint8ClampedArray.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Int16Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5"); 21 | $jscomp.polyfill("Uint16Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Int32Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Uint32Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Float32Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Float64Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5"); 22 | var DracoDecoderModule=function(){var h="undefined"!==typeof document&&document.currentScript?document.currentScript.src:void 0;"undefined"!==typeof __filename&&(h=h||__filename);return function(n){function k(e){return a.locateFile?a.locateFile(e,U):U+e}function p(e,b){if(e){var c=ia;var d=e+b;for(b=e;c[b]&&!(b>=d);)++b;if(16g?d+=String.fromCharCode(g):(g-=65536,d+=String.fromCharCode(55296|g>>10,56320|g&1023))}}else d+=String.fromCharCode(g)}c=d}}else c="";return c}function l(){var e=ja.buffer;a.HEAP8=W=new Int8Array(e);a.HEAP16=new Int16Array(e);a.HEAP32=ca=new Int32Array(e);a.HEAPU8=ia=new Uint8Array(e);a.HEAPU16=new Uint16Array(e);a.HEAPU32=Y=new Uint32Array(e);a.HEAPF32=new Float32Array(e);a.HEAPF64=new Float64Array(e)}function y(e){if(a.onAbort)a.onAbort(e); 24 | e="Aborted("+e+")";da(e);sa=!0;e=new WebAssembly.RuntimeError(e+". Build with -sASSERTIONS for more info.");ka(e);throw e;}function f(e){try{if(e==P&&ea)return new Uint8Array(ea);if(ma)return ma(e);throw"both async and sync fetching of the wasm failed";}catch(b){y(b)}}function q(){if(!ea&&(ta||fa)){if("function"==typeof fetch&&!P.startsWith("file://"))return fetch(P,{credentials:"same-origin"}).then(function(e){if(!e.ok)throw"failed to load wasm binary file at '"+P+"'";return e.arrayBuffer()}).catch(function(){return f(P)}); 25 | if(na)return new Promise(function(e,b){na(P,function(c){e(new Uint8Array(c))},b)})}return Promise.resolve().then(function(){return f(P)})}function u(e){for(;0>2]=b};this.get_type=function(){return Y[this.ptr+4>>2]};this.set_destructor=function(b){Y[this.ptr+8>>2]=b};this.get_destructor=function(){return Y[this.ptr+8>>2]};this.set_refcount=function(b){ca[this.ptr>>2]=b};this.set_caught=function(b){W[this.ptr+ 26 | 12>>0]=b?1:0};this.get_caught=function(){return 0!=W[this.ptr+12>>0]};this.set_rethrown=function(b){W[this.ptr+13>>0]=b?1:0};this.get_rethrown=function(){return 0!=W[this.ptr+13>>0]};this.init=function(b,c){this.set_adjusted_ptr(0);this.set_type(b);this.set_destructor(c);this.set_refcount(0);this.set_caught(!1);this.set_rethrown(!1)};this.add_ref=function(){ca[this.ptr>>2]+=1};this.release_ref=function(){var b=ca[this.ptr>>2];ca[this.ptr>>2]=b-1;return 1===b};this.set_adjusted_ptr=function(b){Y[this.ptr+ 27 | 16>>2]=b};this.get_adjusted_ptr=function(){return Y[this.ptr+16>>2]};this.get_exception_ptr=function(){if(ua(this.get_type()))return Y[this.excPtr>>2];var b=this.get_adjusted_ptr();return 0!==b?b:this.excPtr}}function F(){function e(){if(!la&&(la=!0,a.calledRun=!0,!sa)){va=!0;u(oa);wa(a);if(a.onRuntimeInitialized)a.onRuntimeInitialized();if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;)xa.unshift(a.postRun.shift());u(xa)}}if(!(0=d?b++:2047>=d?b+=2:55296<=d&&57343>= 29 | d?(b+=4,++c):b+=3}b=Array(b+1);c=0;d=b.length;if(0=t){var aa=e.charCodeAt(++g);t=65536+((t&1023)<<10)|aa&1023}if(127>=t){if(c>=d)break;b[c++]=t}else{if(2047>=t){if(c+1>=d)break;b[c++]=192|t>>6}else{if(65535>=t){if(c+2>=d)break;b[c++]=224|t>>12}else{if(c+3>=d)break;b[c++]=240|t>>18;b[c++]=128|t>>12&63}b[c++]=128|t>>6&63}b[c++]=128|t&63}}b[c]=0}e=r.alloc(b,W);r.copy(b,W,e);return e}return e}function Z(e){if("object"=== 30 | typeof e){var b=r.alloc(e,W);r.copy(e,W,b);return b}return e}function X(){throw"cannot construct a VoidPtr, no constructor in IDL";}function S(){this.ptr=za();w(S)[this.ptr]=this}function Q(){this.ptr=Aa();w(Q)[this.ptr]=this}function V(){this.ptr=Ba();w(V)[this.ptr]=this}function x(){this.ptr=Ca();w(x)[this.ptr]=this}function D(){this.ptr=Da();w(D)[this.ptr]=this}function G(){this.ptr=Ea();w(G)[this.ptr]=this}function H(){this.ptr=Fa();w(H)[this.ptr]=this}function E(){this.ptr=Ga();w(E)[this.ptr]= 31 | this}function T(){this.ptr=Ha();w(T)[this.ptr]=this}function C(){throw"cannot construct a Status, no constructor in IDL";}function I(){this.ptr=Ia();w(I)[this.ptr]=this}function J(){this.ptr=Ja();w(J)[this.ptr]=this}function K(){this.ptr=Ka();w(K)[this.ptr]=this}function L(){this.ptr=La();w(L)[this.ptr]=this}function M(){this.ptr=Ma();w(M)[this.ptr]=this}function N(){this.ptr=Na();w(N)[this.ptr]=this}function O(){this.ptr=Oa();w(O)[this.ptr]=this}function z(){this.ptr=Pa();w(z)[this.ptr]=this}function m(){this.ptr= 32 | Qa();w(m)[this.ptr]=this}n=void 0===n?{}:n;var a="undefined"!=typeof n?n:{},wa,ka;a.ready=new Promise(function(e,b){wa=e;ka=b});var Ra=!1,Sa=!1;a.onRuntimeInitialized=function(){Ra=!0;if(Sa&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.onModuleParsed=function(){Sa=!0;if(Ra&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.isVersionSupported=function(e){if("string"!==typeof e)return!1;e=e.split(".");return 2>e.length||3=e[1]?!0:0!=e[0]||10< 33 | e[1]?!1:!0};var Ta=Object.assign({},a),ta="object"==typeof window,fa="function"==typeof importScripts,Ua="object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node,U="";if(Ua){var Va=require("fs"),pa=require("path");U=fa?pa.dirname(U)+"/":__dirname+"/";var Wa=function(e,b){e=e.startsWith("file://")?new URL(e):pa.normalize(e);return Va.readFileSync(e,b?void 0:"utf8")};var ma=function(e){e=Wa(e,!0);e.buffer||(e=new Uint8Array(e));return e};var na=function(e, 34 | b,c){e=e.startsWith("file://")?new URL(e):pa.normalize(e);Va.readFile(e,function(d,g){d?c(d):b(g.buffer)})};1>>=0;if(2147483648=c;c*=2){var d=b*(1+.2/c);d=Math.min(d,e+100663296);var g=Math;d=Math.max(e,d);g=g.min.call(g,2147483648,d+(65536-d%65536)%65536);a:{d=ja.buffer;try{ja.grow(g-d.byteLength+65535>>>16);l();var t=1;break a}catch(aa){}t=void 0}if(t)return!0}return!1}};(function(){function e(g,t){a.asm=g.exports;ja=a.asm.e;l();oa.unshift(a.asm.f);ba--;a.monitorRunDependencies&&a.monitorRunDependencies(ba);0==ba&&(null!==qa&&(clearInterval(qa),qa=null),ha&&(g=ha,ha=null,g()))}function b(g){e(g.instance)} 38 | function c(g){return q().then(function(t){return WebAssembly.instantiate(t,d)}).then(function(t){return t}).then(g,function(t){da("failed to asynchronously prepare wasm: "+t);y(t)})}var d={a:qd};ba++;a.monitorRunDependencies&&a.monitorRunDependencies(ba);if(a.instantiateWasm)try{return a.instantiateWasm(d,e)}catch(g){da("Module.instantiateWasm callback failed with error: "+g),ka(g)}(function(){return ea||"function"!=typeof WebAssembly.instantiateStreaming||P.startsWith("data:application/octet-stream;base64,")|| 39 | P.startsWith("file://")||Ua||"function"!=typeof fetch?c(b):fetch(P,{credentials:"same-origin"}).then(function(g){return WebAssembly.instantiateStreaming(g,d).then(b,function(t){da("wasm streaming compile failed: "+t);da("falling back to ArrayBuffer instantiation");return c(b)})})})().catch(ka);return{}})();var Xa=a._emscripten_bind_VoidPtr___destroy___0=function(){return(Xa=a._emscripten_bind_VoidPtr___destroy___0=a.asm.h).apply(null,arguments)},za=a._emscripten_bind_DecoderBuffer_DecoderBuffer_0= 40 | function(){return(za=a._emscripten_bind_DecoderBuffer_DecoderBuffer_0=a.asm.i).apply(null,arguments)},Ya=a._emscripten_bind_DecoderBuffer_Init_2=function(){return(Ya=a._emscripten_bind_DecoderBuffer_Init_2=a.asm.j).apply(null,arguments)},Za=a._emscripten_bind_DecoderBuffer___destroy___0=function(){return(Za=a._emscripten_bind_DecoderBuffer___destroy___0=a.asm.k).apply(null,arguments)},Aa=a._emscripten_bind_AttributeTransformData_AttributeTransformData_0=function(){return(Aa=a._emscripten_bind_AttributeTransformData_AttributeTransformData_0= 41 | a.asm.l).apply(null,arguments)},$a=a._emscripten_bind_AttributeTransformData_transform_type_0=function(){return($a=a._emscripten_bind_AttributeTransformData_transform_type_0=a.asm.m).apply(null,arguments)},ab=a._emscripten_bind_AttributeTransformData___destroy___0=function(){return(ab=a._emscripten_bind_AttributeTransformData___destroy___0=a.asm.n).apply(null,arguments)},Ba=a._emscripten_bind_GeometryAttribute_GeometryAttribute_0=function(){return(Ba=a._emscripten_bind_GeometryAttribute_GeometryAttribute_0= 42 | a.asm.o).apply(null,arguments)},bb=a._emscripten_bind_GeometryAttribute___destroy___0=function(){return(bb=a._emscripten_bind_GeometryAttribute___destroy___0=a.asm.p).apply(null,arguments)},Ca=a._emscripten_bind_PointAttribute_PointAttribute_0=function(){return(Ca=a._emscripten_bind_PointAttribute_PointAttribute_0=a.asm.q).apply(null,arguments)},cb=a._emscripten_bind_PointAttribute_size_0=function(){return(cb=a._emscripten_bind_PointAttribute_size_0=a.asm.r).apply(null,arguments)},db=a._emscripten_bind_PointAttribute_GetAttributeTransformData_0= 43 | function(){return(db=a._emscripten_bind_PointAttribute_GetAttributeTransformData_0=a.asm.s).apply(null,arguments)},eb=a._emscripten_bind_PointAttribute_attribute_type_0=function(){return(eb=a._emscripten_bind_PointAttribute_attribute_type_0=a.asm.t).apply(null,arguments)},fb=a._emscripten_bind_PointAttribute_data_type_0=function(){return(fb=a._emscripten_bind_PointAttribute_data_type_0=a.asm.u).apply(null,arguments)},gb=a._emscripten_bind_PointAttribute_num_components_0=function(){return(gb=a._emscripten_bind_PointAttribute_num_components_0= 44 | a.asm.v).apply(null,arguments)},hb=a._emscripten_bind_PointAttribute_normalized_0=function(){return(hb=a._emscripten_bind_PointAttribute_normalized_0=a.asm.w).apply(null,arguments)},ib=a._emscripten_bind_PointAttribute_byte_stride_0=function(){return(ib=a._emscripten_bind_PointAttribute_byte_stride_0=a.asm.x).apply(null,arguments)},jb=a._emscripten_bind_PointAttribute_byte_offset_0=function(){return(jb=a._emscripten_bind_PointAttribute_byte_offset_0=a.asm.y).apply(null,arguments)},kb=a._emscripten_bind_PointAttribute_unique_id_0= 45 | function(){return(kb=a._emscripten_bind_PointAttribute_unique_id_0=a.asm.z).apply(null,arguments)},lb=a._emscripten_bind_PointAttribute___destroy___0=function(){return(lb=a._emscripten_bind_PointAttribute___destroy___0=a.asm.A).apply(null,arguments)},Da=a._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0=function(){return(Da=a._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0=a.asm.B).apply(null,arguments)},mb=a._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1= 46 | function(){return(mb=a._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1=a.asm.C).apply(null,arguments)},nb=a._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0=function(){return(nb=a._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0=a.asm.D).apply(null,arguments)},ob=a._emscripten_bind_AttributeQuantizationTransform_min_value_1=function(){return(ob=a._emscripten_bind_AttributeQuantizationTransform_min_value_1=a.asm.E).apply(null,arguments)},pb= 47 | a._emscripten_bind_AttributeQuantizationTransform_range_0=function(){return(pb=a._emscripten_bind_AttributeQuantizationTransform_range_0=a.asm.F).apply(null,arguments)},qb=a._emscripten_bind_AttributeQuantizationTransform___destroy___0=function(){return(qb=a._emscripten_bind_AttributeQuantizationTransform___destroy___0=a.asm.G).apply(null,arguments)},Ea=a._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0=function(){return(Ea=a._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0= 48 | a.asm.H).apply(null,arguments)},rb=a._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1=function(){return(rb=a._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1=a.asm.I).apply(null,arguments)},sb=a._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0=function(){return(sb=a._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0=a.asm.J).apply(null,arguments)},tb=a._emscripten_bind_AttributeOctahedronTransform___destroy___0=function(){return(tb= 49 | a._emscripten_bind_AttributeOctahedronTransform___destroy___0=a.asm.K).apply(null,arguments)},Fa=a._emscripten_bind_PointCloud_PointCloud_0=function(){return(Fa=a._emscripten_bind_PointCloud_PointCloud_0=a.asm.L).apply(null,arguments)},ub=a._emscripten_bind_PointCloud_num_attributes_0=function(){return(ub=a._emscripten_bind_PointCloud_num_attributes_0=a.asm.M).apply(null,arguments)},vb=a._emscripten_bind_PointCloud_num_points_0=function(){return(vb=a._emscripten_bind_PointCloud_num_points_0=a.asm.N).apply(null, 50 | arguments)},wb=a._emscripten_bind_PointCloud___destroy___0=function(){return(wb=a._emscripten_bind_PointCloud___destroy___0=a.asm.O).apply(null,arguments)},Ga=a._emscripten_bind_Mesh_Mesh_0=function(){return(Ga=a._emscripten_bind_Mesh_Mesh_0=a.asm.P).apply(null,arguments)},xb=a._emscripten_bind_Mesh_num_faces_0=function(){return(xb=a._emscripten_bind_Mesh_num_faces_0=a.asm.Q).apply(null,arguments)},yb=a._emscripten_bind_Mesh_num_attributes_0=function(){return(yb=a._emscripten_bind_Mesh_num_attributes_0= 51 | a.asm.R).apply(null,arguments)},zb=a._emscripten_bind_Mesh_num_points_0=function(){return(zb=a._emscripten_bind_Mesh_num_points_0=a.asm.S).apply(null,arguments)},Ab=a._emscripten_bind_Mesh___destroy___0=function(){return(Ab=a._emscripten_bind_Mesh___destroy___0=a.asm.T).apply(null,arguments)},Ha=a._emscripten_bind_Metadata_Metadata_0=function(){return(Ha=a._emscripten_bind_Metadata_Metadata_0=a.asm.U).apply(null,arguments)},Bb=a._emscripten_bind_Metadata___destroy___0=function(){return(Bb=a._emscripten_bind_Metadata___destroy___0= 52 | a.asm.V).apply(null,arguments)},Cb=a._emscripten_bind_Status_code_0=function(){return(Cb=a._emscripten_bind_Status_code_0=a.asm.W).apply(null,arguments)},Db=a._emscripten_bind_Status_ok_0=function(){return(Db=a._emscripten_bind_Status_ok_0=a.asm.X).apply(null,arguments)},Eb=a._emscripten_bind_Status_error_msg_0=function(){return(Eb=a._emscripten_bind_Status_error_msg_0=a.asm.Y).apply(null,arguments)},Fb=a._emscripten_bind_Status___destroy___0=function(){return(Fb=a._emscripten_bind_Status___destroy___0= 53 | a.asm.Z).apply(null,arguments)},Ia=a._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0=function(){return(Ia=a._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0=a.asm._).apply(null,arguments)},Gb=a._emscripten_bind_DracoFloat32Array_GetValue_1=function(){return(Gb=a._emscripten_bind_DracoFloat32Array_GetValue_1=a.asm.$).apply(null,arguments)},Hb=a._emscripten_bind_DracoFloat32Array_size_0=function(){return(Hb=a._emscripten_bind_DracoFloat32Array_size_0=a.asm.aa).apply(null,arguments)},Ib= 54 | a._emscripten_bind_DracoFloat32Array___destroy___0=function(){return(Ib=a._emscripten_bind_DracoFloat32Array___destroy___0=a.asm.ba).apply(null,arguments)},Ja=a._emscripten_bind_DracoInt8Array_DracoInt8Array_0=function(){return(Ja=a._emscripten_bind_DracoInt8Array_DracoInt8Array_0=a.asm.ca).apply(null,arguments)},Jb=a._emscripten_bind_DracoInt8Array_GetValue_1=function(){return(Jb=a._emscripten_bind_DracoInt8Array_GetValue_1=a.asm.da).apply(null,arguments)},Kb=a._emscripten_bind_DracoInt8Array_size_0= 55 | function(){return(Kb=a._emscripten_bind_DracoInt8Array_size_0=a.asm.ea).apply(null,arguments)},Lb=a._emscripten_bind_DracoInt8Array___destroy___0=function(){return(Lb=a._emscripten_bind_DracoInt8Array___destroy___0=a.asm.fa).apply(null,arguments)},Ka=a._emscripten_bind_DracoUInt8Array_DracoUInt8Array_0=function(){return(Ka=a._emscripten_bind_DracoUInt8Array_DracoUInt8Array_0=a.asm.ga).apply(null,arguments)},Mb=a._emscripten_bind_DracoUInt8Array_GetValue_1=function(){return(Mb=a._emscripten_bind_DracoUInt8Array_GetValue_1= 56 | a.asm.ha).apply(null,arguments)},Nb=a._emscripten_bind_DracoUInt8Array_size_0=function(){return(Nb=a._emscripten_bind_DracoUInt8Array_size_0=a.asm.ia).apply(null,arguments)},Ob=a._emscripten_bind_DracoUInt8Array___destroy___0=function(){return(Ob=a._emscripten_bind_DracoUInt8Array___destroy___0=a.asm.ja).apply(null,arguments)},La=a._emscripten_bind_DracoInt16Array_DracoInt16Array_0=function(){return(La=a._emscripten_bind_DracoInt16Array_DracoInt16Array_0=a.asm.ka).apply(null,arguments)},Pb=a._emscripten_bind_DracoInt16Array_GetValue_1= 57 | function(){return(Pb=a._emscripten_bind_DracoInt16Array_GetValue_1=a.asm.la).apply(null,arguments)},Qb=a._emscripten_bind_DracoInt16Array_size_0=function(){return(Qb=a._emscripten_bind_DracoInt16Array_size_0=a.asm.ma).apply(null,arguments)},Rb=a._emscripten_bind_DracoInt16Array___destroy___0=function(){return(Rb=a._emscripten_bind_DracoInt16Array___destroy___0=a.asm.na).apply(null,arguments)},Ma=a._emscripten_bind_DracoUInt16Array_DracoUInt16Array_0=function(){return(Ma=a._emscripten_bind_DracoUInt16Array_DracoUInt16Array_0= 58 | a.asm.oa).apply(null,arguments)},Sb=a._emscripten_bind_DracoUInt16Array_GetValue_1=function(){return(Sb=a._emscripten_bind_DracoUInt16Array_GetValue_1=a.asm.pa).apply(null,arguments)},Tb=a._emscripten_bind_DracoUInt16Array_size_0=function(){return(Tb=a._emscripten_bind_DracoUInt16Array_size_0=a.asm.qa).apply(null,arguments)},Ub=a._emscripten_bind_DracoUInt16Array___destroy___0=function(){return(Ub=a._emscripten_bind_DracoUInt16Array___destroy___0=a.asm.ra).apply(null,arguments)},Na=a._emscripten_bind_DracoInt32Array_DracoInt32Array_0= 59 | function(){return(Na=a._emscripten_bind_DracoInt32Array_DracoInt32Array_0=a.asm.sa).apply(null,arguments)},Vb=a._emscripten_bind_DracoInt32Array_GetValue_1=function(){return(Vb=a._emscripten_bind_DracoInt32Array_GetValue_1=a.asm.ta).apply(null,arguments)},Wb=a._emscripten_bind_DracoInt32Array_size_0=function(){return(Wb=a._emscripten_bind_DracoInt32Array_size_0=a.asm.ua).apply(null,arguments)},Xb=a._emscripten_bind_DracoInt32Array___destroy___0=function(){return(Xb=a._emscripten_bind_DracoInt32Array___destroy___0= 60 | a.asm.va).apply(null,arguments)},Oa=a._emscripten_bind_DracoUInt32Array_DracoUInt32Array_0=function(){return(Oa=a._emscripten_bind_DracoUInt32Array_DracoUInt32Array_0=a.asm.wa).apply(null,arguments)},Yb=a._emscripten_bind_DracoUInt32Array_GetValue_1=function(){return(Yb=a._emscripten_bind_DracoUInt32Array_GetValue_1=a.asm.xa).apply(null,arguments)},Zb=a._emscripten_bind_DracoUInt32Array_size_0=function(){return(Zb=a._emscripten_bind_DracoUInt32Array_size_0=a.asm.ya).apply(null,arguments)},$b=a._emscripten_bind_DracoUInt32Array___destroy___0= 61 | function(){return($b=a._emscripten_bind_DracoUInt32Array___destroy___0=a.asm.za).apply(null,arguments)},Pa=a._emscripten_bind_MetadataQuerier_MetadataQuerier_0=function(){return(Pa=a._emscripten_bind_MetadataQuerier_MetadataQuerier_0=a.asm.Aa).apply(null,arguments)},ac=a._emscripten_bind_MetadataQuerier_HasEntry_2=function(){return(ac=a._emscripten_bind_MetadataQuerier_HasEntry_2=a.asm.Ba).apply(null,arguments)},bc=a._emscripten_bind_MetadataQuerier_GetIntEntry_2=function(){return(bc=a._emscripten_bind_MetadataQuerier_GetIntEntry_2= 62 | a.asm.Ca).apply(null,arguments)},cc=a._emscripten_bind_MetadataQuerier_GetIntEntryArray_3=function(){return(cc=a._emscripten_bind_MetadataQuerier_GetIntEntryArray_3=a.asm.Da).apply(null,arguments)},dc=a._emscripten_bind_MetadataQuerier_GetDoubleEntry_2=function(){return(dc=a._emscripten_bind_MetadataQuerier_GetDoubleEntry_2=a.asm.Ea).apply(null,arguments)},ec=a._emscripten_bind_MetadataQuerier_GetStringEntry_2=function(){return(ec=a._emscripten_bind_MetadataQuerier_GetStringEntry_2=a.asm.Fa).apply(null, 63 | arguments)},fc=a._emscripten_bind_MetadataQuerier_NumEntries_1=function(){return(fc=a._emscripten_bind_MetadataQuerier_NumEntries_1=a.asm.Ga).apply(null,arguments)},gc=a._emscripten_bind_MetadataQuerier_GetEntryName_2=function(){return(gc=a._emscripten_bind_MetadataQuerier_GetEntryName_2=a.asm.Ha).apply(null,arguments)},hc=a._emscripten_bind_MetadataQuerier___destroy___0=function(){return(hc=a._emscripten_bind_MetadataQuerier___destroy___0=a.asm.Ia).apply(null,arguments)},Qa=a._emscripten_bind_Decoder_Decoder_0= 64 | function(){return(Qa=a._emscripten_bind_Decoder_Decoder_0=a.asm.Ja).apply(null,arguments)},ic=a._emscripten_bind_Decoder_DecodeArrayToPointCloud_3=function(){return(ic=a._emscripten_bind_Decoder_DecodeArrayToPointCloud_3=a.asm.Ka).apply(null,arguments)},jc=a._emscripten_bind_Decoder_DecodeArrayToMesh_3=function(){return(jc=a._emscripten_bind_Decoder_DecodeArrayToMesh_3=a.asm.La).apply(null,arguments)},kc=a._emscripten_bind_Decoder_GetAttributeId_2=function(){return(kc=a._emscripten_bind_Decoder_GetAttributeId_2= 65 | a.asm.Ma).apply(null,arguments)},lc=a._emscripten_bind_Decoder_GetAttributeIdByName_2=function(){return(lc=a._emscripten_bind_Decoder_GetAttributeIdByName_2=a.asm.Na).apply(null,arguments)},mc=a._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3=function(){return(mc=a._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3=a.asm.Oa).apply(null,arguments)},nc=a._emscripten_bind_Decoder_GetAttribute_2=function(){return(nc=a._emscripten_bind_Decoder_GetAttribute_2=a.asm.Pa).apply(null,arguments)}, 66 | oc=a._emscripten_bind_Decoder_GetAttributeByUniqueId_2=function(){return(oc=a._emscripten_bind_Decoder_GetAttributeByUniqueId_2=a.asm.Qa).apply(null,arguments)},pc=a._emscripten_bind_Decoder_GetMetadata_1=function(){return(pc=a._emscripten_bind_Decoder_GetMetadata_1=a.asm.Ra).apply(null,arguments)},qc=a._emscripten_bind_Decoder_GetAttributeMetadata_2=function(){return(qc=a._emscripten_bind_Decoder_GetAttributeMetadata_2=a.asm.Sa).apply(null,arguments)},rc=a._emscripten_bind_Decoder_GetFaceFromMesh_3= 67 | function(){return(rc=a._emscripten_bind_Decoder_GetFaceFromMesh_3=a.asm.Ta).apply(null,arguments)},sc=a._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2=function(){return(sc=a._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2=a.asm.Ua).apply(null,arguments)},tc=a._emscripten_bind_Decoder_GetTrianglesUInt16Array_3=function(){return(tc=a._emscripten_bind_Decoder_GetTrianglesUInt16Array_3=a.asm.Va).apply(null,arguments)},uc=a._emscripten_bind_Decoder_GetTrianglesUInt32Array_3=function(){return(uc= 68 | a._emscripten_bind_Decoder_GetTrianglesUInt32Array_3=a.asm.Wa).apply(null,arguments)},vc=a._emscripten_bind_Decoder_GetAttributeFloat_3=function(){return(vc=a._emscripten_bind_Decoder_GetAttributeFloat_3=a.asm.Xa).apply(null,arguments)},wc=a._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3=function(){return(wc=a._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3=a.asm.Ya).apply(null,arguments)},xc=a._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3=function(){return(xc=a._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3= 69 | a.asm.Za).apply(null,arguments)},yc=a._emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3=function(){return(yc=a._emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3=a.asm._a).apply(null,arguments)},zc=a._emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3=function(){return(zc=a._emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3=a.asm.$a).apply(null,arguments)},Ac=a._emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3=function(){return(Ac=a._emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3= 70 | a.asm.ab).apply(null,arguments)},Bc=a._emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3=function(){return(Bc=a._emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3=a.asm.bb).apply(null,arguments)},Cc=a._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3=function(){return(Cc=a._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3=a.asm.cb).apply(null,arguments)},Dc=a._emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3=function(){return(Dc=a._emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3= 71 | a.asm.db).apply(null,arguments)},Ec=a._emscripten_bind_Decoder_GetAttributeDataArrayForAllPoints_5=function(){return(Ec=a._emscripten_bind_Decoder_GetAttributeDataArrayForAllPoints_5=a.asm.eb).apply(null,arguments)},Fc=a._emscripten_bind_Decoder_SkipAttributeTransform_1=function(){return(Fc=a._emscripten_bind_Decoder_SkipAttributeTransform_1=a.asm.fb).apply(null,arguments)},Gc=a._emscripten_bind_Decoder_GetEncodedGeometryType_Deprecated_1=function(){return(Gc=a._emscripten_bind_Decoder_GetEncodedGeometryType_Deprecated_1= 72 | a.asm.gb).apply(null,arguments)},Hc=a._emscripten_bind_Decoder_DecodeBufferToPointCloud_2=function(){return(Hc=a._emscripten_bind_Decoder_DecodeBufferToPointCloud_2=a.asm.hb).apply(null,arguments)},Ic=a._emscripten_bind_Decoder_DecodeBufferToMesh_2=function(){return(Ic=a._emscripten_bind_Decoder_DecodeBufferToMesh_2=a.asm.ib).apply(null,arguments)},Jc=a._emscripten_bind_Decoder___destroy___0=function(){return(Jc=a._emscripten_bind_Decoder___destroy___0=a.asm.jb).apply(null,arguments)},Kc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM= 73 | function(){return(Kc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM=a.asm.kb).apply(null,arguments)},Lc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM=function(){return(Lc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM=a.asm.lb).apply(null,arguments)},Mc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM=function(){return(Mc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM= 74 | a.asm.mb).apply(null,arguments)},Nc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM=function(){return(Nc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM=a.asm.nb).apply(null,arguments)},Oc=a._emscripten_enum_draco_GeometryAttribute_Type_INVALID=function(){return(Oc=a._emscripten_enum_draco_GeometryAttribute_Type_INVALID=a.asm.ob).apply(null,arguments)},Pc=a._emscripten_enum_draco_GeometryAttribute_Type_POSITION=function(){return(Pc=a._emscripten_enum_draco_GeometryAttribute_Type_POSITION= 75 | a.asm.pb).apply(null,arguments)},Qc=a._emscripten_enum_draco_GeometryAttribute_Type_NORMAL=function(){return(Qc=a._emscripten_enum_draco_GeometryAttribute_Type_NORMAL=a.asm.qb).apply(null,arguments)},Rc=a._emscripten_enum_draco_GeometryAttribute_Type_COLOR=function(){return(Rc=a._emscripten_enum_draco_GeometryAttribute_Type_COLOR=a.asm.rb).apply(null,arguments)},Sc=a._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD=function(){return(Sc=a._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD= 76 | a.asm.sb).apply(null,arguments)},Tc=a._emscripten_enum_draco_GeometryAttribute_Type_GENERIC=function(){return(Tc=a._emscripten_enum_draco_GeometryAttribute_Type_GENERIC=a.asm.tb).apply(null,arguments)},Uc=a._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE=function(){return(Uc=a._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE=a.asm.ub).apply(null,arguments)},Vc=a._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD=function(){return(Vc=a._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD= 77 | a.asm.vb).apply(null,arguments)},Wc=a._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH=function(){return(Wc=a._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH=a.asm.wb).apply(null,arguments)},Xc=a._emscripten_enum_draco_DataType_DT_INVALID=function(){return(Xc=a._emscripten_enum_draco_DataType_DT_INVALID=a.asm.xb).apply(null,arguments)},Yc=a._emscripten_enum_draco_DataType_DT_INT8=function(){return(Yc=a._emscripten_enum_draco_DataType_DT_INT8=a.asm.yb).apply(null,arguments)},Zc= 78 | a._emscripten_enum_draco_DataType_DT_UINT8=function(){return(Zc=a._emscripten_enum_draco_DataType_DT_UINT8=a.asm.zb).apply(null,arguments)},$c=a._emscripten_enum_draco_DataType_DT_INT16=function(){return($c=a._emscripten_enum_draco_DataType_DT_INT16=a.asm.Ab).apply(null,arguments)},ad=a._emscripten_enum_draco_DataType_DT_UINT16=function(){return(ad=a._emscripten_enum_draco_DataType_DT_UINT16=a.asm.Bb).apply(null,arguments)},bd=a._emscripten_enum_draco_DataType_DT_INT32=function(){return(bd=a._emscripten_enum_draco_DataType_DT_INT32= 79 | a.asm.Cb).apply(null,arguments)},cd=a._emscripten_enum_draco_DataType_DT_UINT32=function(){return(cd=a._emscripten_enum_draco_DataType_DT_UINT32=a.asm.Db).apply(null,arguments)},dd=a._emscripten_enum_draco_DataType_DT_INT64=function(){return(dd=a._emscripten_enum_draco_DataType_DT_INT64=a.asm.Eb).apply(null,arguments)},ed=a._emscripten_enum_draco_DataType_DT_UINT64=function(){return(ed=a._emscripten_enum_draco_DataType_DT_UINT64=a.asm.Fb).apply(null,arguments)},fd=a._emscripten_enum_draco_DataType_DT_FLOAT32= 80 | function(){return(fd=a._emscripten_enum_draco_DataType_DT_FLOAT32=a.asm.Gb).apply(null,arguments)},gd=a._emscripten_enum_draco_DataType_DT_FLOAT64=function(){return(gd=a._emscripten_enum_draco_DataType_DT_FLOAT64=a.asm.Hb).apply(null,arguments)},hd=a._emscripten_enum_draco_DataType_DT_BOOL=function(){return(hd=a._emscripten_enum_draco_DataType_DT_BOOL=a.asm.Ib).apply(null,arguments)},id=a._emscripten_enum_draco_DataType_DT_TYPES_COUNT=function(){return(id=a._emscripten_enum_draco_DataType_DT_TYPES_COUNT= 81 | a.asm.Jb).apply(null,arguments)},jd=a._emscripten_enum_draco_StatusCode_OK=function(){return(jd=a._emscripten_enum_draco_StatusCode_OK=a.asm.Kb).apply(null,arguments)},kd=a._emscripten_enum_draco_StatusCode_DRACO_ERROR=function(){return(kd=a._emscripten_enum_draco_StatusCode_DRACO_ERROR=a.asm.Lb).apply(null,arguments)},ld=a._emscripten_enum_draco_StatusCode_IO_ERROR=function(){return(ld=a._emscripten_enum_draco_StatusCode_IO_ERROR=a.asm.Mb).apply(null,arguments)},md=a._emscripten_enum_draco_StatusCode_INVALID_PARAMETER= 82 | function(){return(md=a._emscripten_enum_draco_StatusCode_INVALID_PARAMETER=a.asm.Nb).apply(null,arguments)},nd=a._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION=function(){return(nd=a._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION=a.asm.Ob).apply(null,arguments)},od=a._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION=function(){return(od=a._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION=a.asm.Pb).apply(null,arguments)};a._malloc=function(){return(a._malloc=a.asm.Qb).apply(null,arguments)}; 83 | a._free=function(){return(a._free=a.asm.Rb).apply(null,arguments)};var ua=function(){return(ua=a.asm.Sb).apply(null,arguments)};a.___start_em_js=11660;a.___stop_em_js=11758;var la;ha=function b(){la||F();la||(ha=b)};if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0=r.size?(0>>=0;switch(c.BYTES_PER_ELEMENT){case 2:d>>>=1;break;case 4:d>>>=2;break;case 8:d>>>=3}for(var g=0;gb.byteLength)return a.INVALID_GEOMETRY_TYPE;switch(b[7]){case 0:return a.POINT_CLOUD;case 1:return a.TRIANGULAR_MESH;default:return a.INVALID_GEOMETRY_TYPE}};return n.ready}}();"object"===typeof exports&&"object"===typeof module?module.exports=DracoDecoderModule:"function"===typeof define&&define.amd?define([],function(){return DracoDecoderModule}):"object"===typeof exports&&(exports.DracoDecoderModule=DracoDecoderModule); 117 | -------------------------------------------------------------------------------- /public/uvGrid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomorrowevening/three-offscreen/785a96a2967e59f484efd97dea4e2cdd08468d2d/public/uvGrid.jpg -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Wrapper.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef, useState } from 'react' 2 | import { getGPUTier, TierResult } from 'detect-gpu' 3 | import Workers from './webworker/workers' 4 | import CanvasComponent from './canvas/CanvasComponent' 5 | import Loader from './components/Loader' 6 | import Settings from './global/settings' 7 | import { QualityType } from './types' 8 | 9 | export default function Wrapper() { 10 | const canvasRef = useRef(null) 11 | const [ready, setReady] = useState(false) 12 | 13 | useEffect(() => { 14 | getGPUTier().then((gpuTier: TierResult) => { 15 | // Detect Support 16 | let supportOffScreenWebGL = false 17 | if (canvasRef.current !== null) { 18 | supportOffScreenWebGL = 'transferControlToOffscreen' in canvasRef.current 19 | 20 | // If it's Safari, then check the version because Safari < 17 doesn't support OffscreenCanvas with a WebGL context. 21 | const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent) 22 | if (isSafari) { 23 | const versionMatch = navigator.userAgent.match( /version\/(\d+)/i ) 24 | const safariVersion = versionMatch ? parseInt( versionMatch[ 1 ] ) : 0 25 | supportOffScreenWebGL = safariVersion >= 17 26 | } 27 | 28 | // Override setting 29 | if (location.hash.search('regular') > -1) supportOffScreenWebGL = false 30 | } 31 | 32 | // Update Settings 33 | Settings.dpr = devicePixelRatio 34 | if (gpuTier.fps !== undefined) Settings.fps = Math.min(gpuTier.fps, 60) // cap FPS to 60 35 | if (gpuTier.isMobile !== undefined) Settings.mobile = gpuTier.isMobile 36 | if (gpuTier.tier === 3) Settings.quality = QualityType.High 37 | else if (gpuTier.tier === 2) Settings.quality = QualityType.Medium 38 | Settings.supportOffScreenCanvas = supportOffScreenWebGL 39 | Settings.width = innerWidth 40 | Settings.height = innerHeight 41 | 42 | Workers.init() 43 | setReady(true) 44 | }) 45 | return () => { 46 | Workers.dispose() 47 | } 48 | }, []) 49 | 50 | return ( 51 | <> 52 | 53 | {ready && canvasRef.current !== null && ( 54 | <> 55 | 56 | 57 | 58 | )} 59 | 60 | ) 61 | } 62 | -------------------------------------------------------------------------------- /src/canvas/CanvasComponent.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from 'react' 2 | import Stats from 'stats-gl' 3 | import OffscreenWay from './OffscreenWay' 4 | import StandardWay from './StandardWay' 5 | import Settings from '../global/settings' 6 | 7 | let interval: number | null = null 8 | 9 | type CanvasComponentProps = { 10 | canvas: HTMLCanvasElement 11 | } 12 | 13 | export default function CanvasComponent(props: CanvasComponentProps) { 14 | // Refs 15 | const buttonRef = useRef(null) 16 | const resultRef = useRef(null) 17 | 18 | function jank() { 19 | let number = 0; 20 | for ( let i = 0; i < 10000000; i ++ ) { 21 | number += Math.random(); 22 | } 23 | 24 | if (resultRef.current) { 25 | resultRef.current.innerHTML = number.toString() 26 | } 27 | } 28 | 29 | function clickButton() { 30 | if ( interval === null ) { 31 | interval = setInterval( jank, 1000 / 60 ) 32 | buttonRef.current!.innerHTML = 'STOP JANK' 33 | } else { 34 | clearInterval( interval ) 35 | interval = null 36 | buttonRef.current!.innerHTML = 'START JANK' 37 | resultRef.current!.innerHTML = '' 38 | } 39 | } 40 | 41 | useEffect(() => { 42 | const stats = new Stats({}) 43 | document.body.appendChild(stats.dom) 44 | 45 | let rafID = -1 46 | const onUpdate = () => { 47 | stats.update() 48 | rafID = requestAnimationFrame(onUpdate) 49 | } 50 | onUpdate() 51 | 52 | return () => { 53 | cancelAnimationFrame(rafID) 54 | rafID = -1 55 | } 56 | }, []) 57 | 58 | return ( 59 | <> 60 |

0

61 | 62 | {Settings.supportOffScreenCanvas ? ( 63 | 64 | ) : ( 65 | 66 | )} 67 | 68 | ) 69 | } 70 | -------------------------------------------------------------------------------- /src/canvas/OffscreenWay.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { MethodProps } from '../types' 3 | import Settings from '../global/settings'; 4 | import Workers from '../webworker/workers' 5 | import { ElementProxy, eventHandlers } from '../webworker/EventHandling'; 6 | 7 | // Component 8 | 9 | export default function OffscreenWay(props: MethodProps) { 10 | useEffect(() => { 11 | console.log('Offscreen Canvas') 12 | 13 | props.canvas.focus() 14 | 15 | if (Workers.canvas) { 16 | const proxy = new ElementProxy(props.canvas, Workers.canvas, eventHandlers) 17 | 18 | // App 19 | const offscreenCanvas = props.canvas.transferControlToOffscreen() 20 | const message = { 21 | ...{ 22 | type: 'init', 23 | canvas: offscreenCanvas, 24 | canvasId: proxy.id, 25 | }, 26 | ...Settings, 27 | } 28 | Workers.canvas.postMessage(message, [offscreenCanvas]) 29 | } 30 | }, [props]) 31 | 32 | return null 33 | } 34 | -------------------------------------------------------------------------------- /src/canvas/StandardWay.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import ThreeApp from '../webgl/ThreeApp' 3 | import { MethodProps } from '../types' 4 | import { dispatcher, Events } from '../global/constants' 5 | import Settings from '../global/settings' 6 | 7 | export default function StandardWay(props: MethodProps) { 8 | useEffect(() => { 9 | console.log('Regular Canvas') 10 | 11 | // App 12 | const newApp = new ThreeApp(props.canvas, props.canvas, Settings) 13 | newApp.play() 14 | 15 | function onLoad(event: any) { 16 | dispatcher.removeEventListener(Events.LoadComplete, onLoad) 17 | newApp.onLoad(event.value) 18 | } 19 | dispatcher.addEventListener(Events.LoadComplete, onLoad) 20 | 21 | return () => { 22 | dispatcher.removeEventListener(Events.LoadComplete, onLoad) 23 | newApp.dispose() 24 | } 25 | }, [props]) 26 | 27 | return null 28 | } -------------------------------------------------------------------------------- /src/components/Loader.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef, useState } from 'react'; 2 | import { assetList, dispatcher, Events } from '../global/constants'; 3 | 4 | export default function Loader() { 5 | const pRef = useRef(null) 6 | const [loaded, setLoaded] = useState(false) 7 | 8 | useEffect(() => { 9 | function onLoad() { 10 | dispatcher.removeEventListener(Events.LoadComplete, onLoad) 11 | setLoaded(true) 12 | } 13 | 14 | dispatcher.addEventListener(Events.LoadComplete, onLoad) 15 | dispatcher.dispatchEvent({ type: Events.LoadStart, value: assetList }) 16 | return () => { 17 | dispatcher.removeEventListener(Events.LoadComplete, onLoad) 18 | } 19 | }, []) 20 | 21 | return ( 22 | <> 23 | {loaded ? null :

0%

} 24 | 25 | ) 26 | } -------------------------------------------------------------------------------- /src/global/constants.ts: -------------------------------------------------------------------------------- 1 | import { EventDispatcher } from 'three' 2 | import { File } from '../types' 3 | 4 | export enum Events { 5 | LoadStart = 'LoadStart', 6 | LoadComplete = 'LoadComplete', 7 | } 8 | 9 | export type WebGLEvent = { 10 | [key in Events]: { value?: unknown } 11 | } 12 | 13 | export const dispatcher = new EventDispatcher() 14 | 15 | export const assetList: File[] = [ 16 | { 17 | type: 'image', 18 | name: 'uvGrid', 19 | file: '/uvGrid.jpg', 20 | }, 21 | { 22 | type: 'image', 23 | name: 'nx', 24 | file: '/cube/nx.png', 25 | }, 26 | { 27 | type: 'image', 28 | name: 'ny', 29 | file: '/cube/ny.png', 30 | }, 31 | { 32 | type: 'image', 33 | name: 'nz', 34 | file: '/cube/nz.png', 35 | }, 36 | { 37 | type: 'image', 38 | name: 'px', 39 | file: '/cube/px.png', 40 | }, 41 | { 42 | type: 'image', 43 | name: 'py', 44 | file: '/cube/py.png', 45 | }, 46 | { 47 | type: 'image', 48 | name: 'pz', 49 | file: '/cube/pz.png', 50 | }, 51 | { 52 | type: 'gltf', 53 | name: 'Horse', 54 | file: '/Horse.glb', 55 | }, 56 | { 57 | type: 'fbx', 58 | name: 'Idle', 59 | file: '/Idle.fbx', 60 | }, 61 | ] 62 | -------------------------------------------------------------------------------- /src/global/settings.ts: -------------------------------------------------------------------------------- 1 | import { AppSettings, QualityType } from '../types'; 2 | 3 | const Settings: AppSettings = { 4 | dpr: 1, 5 | fps: 30, 6 | width: 100, 7 | height: 100, 8 | mobile: false, 9 | supportOffScreenCanvas: false, 10 | quality: QualityType.Low, 11 | } 12 | export default Settings 13 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | a { 17 | font-weight: 500; 18 | color: #646cff; 19 | text-decoration: inherit; 20 | } 21 | a:hover { 22 | color: #535bf2; 23 | } 24 | 25 | html, body { 26 | margin: 0; 27 | padding: 0; 28 | min-width: 100%; 29 | min-height: 100%; 30 | width: 100%; 31 | height: 100%; 32 | overflow: hidden; 33 | } 34 | 35 | #root { 36 | position: absolute; 37 | left: 0; 38 | right: 0; 39 | top: 0; 40 | bottom: 0; 41 | } 42 | 43 | canvas { 44 | max-width: 100%; 45 | max-height: 100%; 46 | } 47 | 48 | h1 { 49 | font-size: 3.2em; 50 | line-height: 1.1; 51 | } 52 | 53 | button { 54 | border-radius: 8px; 55 | border: 1px solid transparent; 56 | padding: 0.6em 1.2em; 57 | font-size: 1em; 58 | font-weight: 500; 59 | font-family: inherit; 60 | background-color: #1a1a1a; 61 | cursor: pointer; 62 | position: absolute; 63 | left: 50%; 64 | top: 0; 65 | transform: translateX(-50%); 66 | } 67 | button:hover { 68 | border-color: #646cff; 69 | } 70 | button:focus, 71 | button:focus-visible { 72 | outline: 4px auto -webkit-focus-ring-color; 73 | } 74 | 75 | p { 76 | color: white; 77 | position: absolute; 78 | left: 50%; 79 | top: 50px; 80 | transform: translateX(-50%); 81 | } 82 | 83 | @media (prefers-color-scheme: light) { 84 | :root { 85 | color: #213547; 86 | background-color: #ffffff; 87 | } 88 | a:hover { 89 | color: #747bff; 90 | } 91 | button { 92 | background-color: #f9f9f9; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import './index.css' 4 | import Wrapper from './Wrapper' 5 | 6 | export const IS_DEV = import.meta.env.MODE === 'development' 7 | 8 | createRoot(document.getElementById('root')!).render( 9 | <> 10 | {IS_DEV ? ( 11 | <> 12 | 13 | 14 | ) : ( 15 | 16 | 17 | 18 | )} 19 | 20 | ) 21 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import { AnimationClip, Object3DJSON } from 'three' 2 | 3 | export type MethodProps = { 4 | canvas: HTMLCanvasElement 5 | } 6 | 7 | export type FileType = 'audio' | 'blob' | 'buffer' | 'fbx' | 'gltf' | 'image' | 'json' | 'video' 8 | 9 | export type File = { 10 | name: string 11 | file: string 12 | type: FileType 13 | } 14 | 15 | export type Assets = { 16 | audio: Map 17 | blob: Map 18 | buffer: Map 19 | image: Map 20 | json: Map 21 | model: Map 22 | video: Map 23 | } 24 | 25 | export type ModelInfo = { 26 | animations: AnimationClip[] 27 | cameras?: Object3DJSON[] 28 | scene: Object3DJSON 29 | } 30 | 31 | export enum QualityType { 32 | 'High', 33 | 'Medium', 34 | 'Low', 35 | } 36 | 37 | export type AppSettings = { 38 | dpr: number 39 | fps: number 40 | width: number 41 | height: number 42 | mobile: boolean 43 | supportOffScreenCanvas: boolean 44 | quality: QualityType 45 | } 46 | -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/webgl/ThreeApp.ts: -------------------------------------------------------------------------------- 1 | import { Clock, WebGLRenderer } from 'three' 2 | import ThreeScene from './ThreeScene' 3 | import { AppSettings, Assets } from '../types' 4 | import { dispose } from './threeUtils' 5 | 6 | export default class ThreeApp { 7 | canvas: HTMLCanvasElement 8 | renderer: WebGLRenderer 9 | scene: ThreeScene 10 | settings: AppSettings 11 | 12 | private inputElement: any 13 | private raf = -1 14 | private clock = new Clock() 15 | 16 | constructor(canvas: HTMLCanvasElement, inputElement: any, settings: AppSettings) { 17 | console.log('Settings:', settings) 18 | this.canvas = canvas 19 | this.inputElement = inputElement 20 | this.settings = settings 21 | 22 | this.renderer = new WebGLRenderer({ canvas }) 23 | this.renderer.setPixelRatio(settings.dpr) 24 | 25 | // Scene 26 | 27 | this.scene = new ThreeScene(this.renderer, inputElement, settings.width, settings.height) 28 | 29 | // Begin App 30 | 31 | this.clock.start() 32 | 33 | inputElement.addEventListener('resize', this.onResize) 34 | this.resize(settings.width, settings.height) 35 | } 36 | 37 | dispose() { 38 | this.pause() 39 | this.inputElement.removeEventListener('resize', this.onResize) 40 | dispose(this.scene) 41 | this.renderer.dispose() 42 | } 43 | 44 | async onLoad(assets: Assets) { 45 | return this.scene.onLoad(assets); 46 | } 47 | 48 | play() { 49 | this.onUpdate() 50 | } 51 | 52 | pause() { 53 | cancelAnimationFrame(this.raf) 54 | this.raf = -1 55 | } 56 | 57 | update() { 58 | const delta = this.clock.getDelta() 59 | this.scene.update(delta) 60 | } 61 | 62 | draw() { 63 | this.scene.draw() 64 | } 65 | 66 | onUpdate = () => { 67 | this.update() 68 | this.draw() 69 | this.raf = requestAnimationFrame(this.onUpdate) 70 | } 71 | 72 | resize(width: number, height: number) { 73 | this.scene.resize(width, height, !this.settings.supportOffScreenCanvas); 74 | 75 | if (this.settings.supportOffScreenCanvas) { 76 | this.inputElement.clientWidth = width 77 | this.inputElement.clientHeight = height 78 | this.inputElement.width = width 79 | this.inputElement.height = height 80 | } 81 | } 82 | 83 | // Handlers 84 | 85 | private onResize = (evt: any) => { 86 | const { width, height } = evt 87 | this.resize(width, height) 88 | } 89 | } -------------------------------------------------------------------------------- /src/webgl/ThreeScene.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AmbientLight, 3 | AnimationMixer, 4 | BoxGeometry, 5 | CubeReflectionMapping, 6 | CubeTexture, 7 | DirectionalLight, 8 | DoubleSide, 9 | HalfFloatType, 10 | Mesh, 11 | MeshBasicMaterial, 12 | MeshStandardMaterial, 13 | PerspectiveCamera, 14 | PlaneGeometry, 15 | Scene, 16 | Texture, 17 | WebGLRenderer, 18 | } from 'three' 19 | import { OrbitControls } from 'three/examples/jsm/Addons.js' 20 | import { EffectComposer, EffectPass, FXAAEffect, RenderPass, VignetteEffect } from 'postprocessing' 21 | import { createModel } from './threeUtils' 22 | import { Assets } from '../types' 23 | 24 | export default class ThreeScene extends Scene { 25 | camera: PerspectiveCamera 26 | cube: Mesh 27 | private composer: EffectComposer 28 | private controls?: OrbitControls 29 | private fbxMixer?: AnimationMixer 30 | private gltfMixer?: AnimationMixer 31 | 32 | constructor(renderer: WebGLRenderer, inputElement: any, width: number, height: number) { 33 | super(); 34 | this.name = 'ThreeScene'; 35 | 36 | this.camera = new PerspectiveCamera(60, width / height, 0.1, 100) 37 | this.camera.position.z = 12 38 | 39 | this.cube = new Mesh(new BoxGeometry(), new MeshStandardMaterial({ roughness: 0.1, metalness: 0.75 })) 40 | this.add(this.cube); 41 | 42 | const light = new DirectionalLight() 43 | light.position.set(3, 5, 5) 44 | this.add(light) 45 | 46 | const ambient = new AmbientLight(0xffffff, 0.1) 47 | this.add(ambient) 48 | 49 | // Post 50 | this.composer = new EffectComposer(renderer, { frameBufferType: HalfFloatType }) 51 | this.composer.addPass(new RenderPass(this, this.camera)) 52 | this.composer.addPass(new EffectPass(this.camera, new FXAAEffect(), new VignetteEffect())) 53 | 54 | // Orbit 55 | // @ts-ignore 56 | this.controls = new OrbitControls(this.camera, inputElement) 57 | this.controls.target.set( 0, 0, 0 ); 58 | this.controls.enableDamping = true 59 | this.controls.maxDistance = 20 60 | this.controls.minDistance = 4 61 | this.controls.update() 62 | } 63 | 64 | dispose() { 65 | this.controls?.dispose(); 66 | } 67 | 68 | update(delta: number) { 69 | this.cube.rotation.x += delta 70 | this.fbxMixer?.update(delta) 71 | this.gltfMixer?.update(delta) 72 | this.controls?.update(delta) 73 | } 74 | 75 | draw() { 76 | this.composer.render() 77 | } 78 | 79 | resize(width: number, height: number, updateStyle: boolean) { 80 | this.camera.aspect = width / height 81 | this.camera.updateProjectionMatrix() 82 | this.composer.setSize(width, height, updateStyle) 83 | } 84 | 85 | async onLoad(assets: Assets) { 86 | // Cube Texture 87 | const cubeTexture = new CubeTexture([ 88 | assets.image.get('px'), 89 | assets.image.get('nx'), 90 | assets.image.get('py'), 91 | assets.image.get('ny'), 92 | assets.image.get('pz'), 93 | assets.image.get('nz'), 94 | ], CubeReflectionMapping) 95 | cubeTexture.needsUpdate = true 96 | this.background = cubeTexture 97 | 98 | // Image 99 | const texture = new Texture(assets.image.get('uvGrid')) 100 | texture.needsUpdate = true 101 | const material = new MeshBasicMaterial({ map: texture, side: DoubleSide }) 102 | const mesh = new Mesh(new PlaneGeometry(), material) 103 | mesh.position.z = -5 104 | mesh.scale.setScalar(6) 105 | mesh.scale.y *= -1 106 | this.add(mesh) 107 | 108 | // FBX 109 | const fbx = await createModel(assets.model.get('Idle')!) 110 | fbx.model.position.set(-1.5, -1, 0) 111 | fbx.model.scale.setScalar(0.01) 112 | this.add(fbx.model) 113 | this.fbxMixer = fbx.mixer 114 | 115 | // GLTF 116 | const gltf = await createModel(assets.model.get('Horse')!) 117 | gltf.model.position.set(1.5, -1, 0) 118 | gltf.model.scale.setScalar(0.01) 119 | this.add(gltf.model) 120 | this.gltfMixer = gltf.mixer 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/webgl/threeUtils.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AnimationClip, 3 | AnimationMixer, 4 | Audio, 5 | Material, 6 | Mesh, 7 | Object3D, 8 | Object3DEventMap, 9 | ObjectLoader, 10 | Texture, 11 | } from 'three'; 12 | import { ModelInfo } from '../types' 13 | 14 | type ParsedModel = { 15 | model: Object3D 16 | mixer: AnimationMixer 17 | cameras: Object3D[] 18 | } 19 | 20 | export function createModel(model: ModelInfo): Promise { 21 | return new Promise((resolve) => { 22 | const loader = new ObjectLoader(); 23 | loader.parseAsync(model.scene).then((scene: Object3D) => { 24 | // Load animations 25 | const mixer = new AnimationMixer(scene); 26 | if (model.animations.length > 0) { 27 | // @ts-ignore 28 | const animations = model.animations.map(data => AnimationClip.parse(data)); 29 | // Play the first animation 30 | const action = mixer.clipAction(animations[0]); 31 | action.play(); 32 | } 33 | 34 | const cameras: Object3D[] = [] 35 | if (model.cameras && model.cameras.length > 0) { 36 | model.cameras.forEach((value: unknown) => { 37 | loader.parseAsync(value).then((camera) => { 38 | cameras.push(camera) 39 | }) 40 | }) 41 | } 42 | 43 | resolve({ 44 | model: scene, 45 | mixer, 46 | cameras, 47 | }); 48 | }) 49 | }) 50 | } 51 | 52 | export const disposeTexture = (texture?: Texture): void => { 53 | texture?.dispose(); 54 | }; 55 | 56 | export const disposeMaterial = (material?: Material | Material[]): void => { 57 | if (!material) return; 58 | 59 | if (Array.isArray(material)) { 60 | material.forEach((mat: Material) => mat.dispose()); 61 | } else { 62 | material.dispose(); 63 | } 64 | }; 65 | 66 | export const dispose = (object: Object3D): void => { 67 | if (!object) return; 68 | 69 | // Dispose children 70 | while (object.children.length > 0) { 71 | const child = object.children[0]; 72 | if (child.type === 'Audio') { 73 | (child as Audio).pause(); 74 | if (child.parent) { 75 | child.parent.remove(child); 76 | } 77 | } else { 78 | dispose(child); 79 | } 80 | } 81 | 82 | // Dispose object 83 | if (object.parent) object.parent.remove(object); 84 | // @ts-ignore 85 | if (object.isMesh) { 86 | const mesh = object as Mesh; 87 | mesh.geometry?.dispose(); 88 | disposeMaterial(mesh.material); 89 | } 90 | 91 | // @ts-ignore 92 | if (object.dispose !== undefined) object.dispose(); 93 | }; 94 | -------------------------------------------------------------------------------- /src/webworker/CanvasWorker.ts: -------------------------------------------------------------------------------- 1 | import { ProxyManager } from './ProxyManager'; 2 | import ThreeApp from '../webgl/ThreeApp' 3 | 4 | let app: ThreeApp 5 | const proxyManager = new ProxyManager(); 6 | 7 | function createApp(data: any) { 8 | const canvas = data.canvas as HTMLCanvasElement 9 | if (!(canvas instanceof OffscreenCanvas)) { 10 | console.log(`Doesn't support offscreen`) 11 | return 12 | } 13 | 14 | const proxy = proxyManager.getProxy(data.canvasId); 15 | app = new ThreeApp(canvas, proxy, data) 16 | app.play() 17 | } 18 | 19 | self.onmessage = (event) => { 20 | const type = event.data.type 21 | switch (type) { 22 | case 'init': 23 | createApp(event.data) 24 | break 25 | case 'loadComplete': 26 | app.onLoad(event.data.data) 27 | break 28 | case 'event': 29 | proxyManager.handleEvent(event.data) 30 | break 31 | case 'makeProxy': 32 | proxyManager.makeProxy(event.data) 33 | break 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/webworker/EventHandling.ts: -------------------------------------------------------------------------------- 1 | // Transfer Events 2 | 3 | type EventHandler = (event: Event, sendFn: (data: any) => void) => void; 4 | 5 | const mouseEventHandler = makeSendPropertiesHandler([ 6 | 'ctrlKey', 7 | 'metaKey', 8 | 'shiftKey', 9 | 'button', 10 | 'pointerId', 11 | 'pointerType', 12 | 'clientX', 13 | 'clientY', 14 | 'pageX', 15 | 'pageY', 16 | ]); 17 | 18 | const wheelEventHandlerImpl = makeSendPropertiesHandler([ 19 | 'clientX', 20 | 'clientY', 21 | 'deltaX', 22 | 'deltaY', 23 | 'deltaMode', 24 | ]); 25 | 26 | const keydownEventHandler = makeSendPropertiesHandler([ 27 | 'ctrlKey', 28 | 'metaKey', 29 | 'shiftKey', 30 | 'keyCode', 31 | ]); 32 | 33 | function wheelEventHandler(event: WheelEvent, sendFn: (data: any) => void): void { 34 | event.preventDefault(); 35 | wheelEventHandlerImpl(event, sendFn); 36 | } 37 | 38 | function preventDefaultHandler(event: Event): void { 39 | event.preventDefault(); 40 | } 41 | 42 | function copyProperties( 43 | src: Record, 44 | properties: string[], 45 | dst: Record 46 | ): void { 47 | for (const name of properties) { 48 | dst[name] = src[name]; 49 | } 50 | } 51 | 52 | function makeSendPropertiesHandler(properties: string[]): EventHandler { 53 | return function sendProperties(event: Event, sendFn: (data: any) => void): void { 54 | const data: Record = { type: event.type }; 55 | copyProperties(event as Record, properties, data); 56 | sendFn(data); 57 | }; 58 | } 59 | 60 | function touchEventHandler(event: TouchEvent, sendFn: (data: any) => void): void { 61 | const touches: Array<{ pageX: number; pageY: number }> = []; 62 | const data = { type: event.type, touches }; 63 | 64 | for (let i = 0; i < event.touches.length; ++i) { 65 | const touch = event.touches[i]; 66 | touches.push({ 67 | pageX: touch.pageX, 68 | pageY: touch.pageY, 69 | }); 70 | } 71 | 72 | sendFn(data); 73 | } 74 | 75 | // The four arrow keys 76 | const orbitKeys: Record = { 77 | '37': true, // left 78 | '38': true, // up 79 | '39': true, // right 80 | '40': true, // down 81 | }; 82 | 83 | function filteredKeydownEventHandler( 84 | event: KeyboardEvent, 85 | sendFn: (data: any) => void 86 | ): void { 87 | const { keyCode } = event; 88 | if (orbitKeys[keyCode]) { 89 | event.preventDefault(); 90 | keydownEventHandler(event, sendFn); 91 | } 92 | } 93 | 94 | // Proxy 95 | 96 | export const eventHandlers: Record = { 97 | contextmenu: preventDefaultHandler, 98 | mousedown: mouseEventHandler, 99 | mousemove: mouseEventHandler, 100 | mouseup: mouseEventHandler, 101 | pointerdown: mouseEventHandler, 102 | pointermove: mouseEventHandler, 103 | pointerup: mouseEventHandler, 104 | touchstart: touchEventHandler, 105 | touchmove: touchEventHandler, 106 | touchend: touchEventHandler, 107 | wheel: wheelEventHandler, 108 | keydown: filteredKeydownEventHandler, 109 | }; 110 | 111 | let nextProxyId = 0; 112 | 113 | export class ElementProxy { 114 | id: number; 115 | worker: Worker; 116 | 117 | constructor( 118 | element: HTMLElement, 119 | worker: Worker, 120 | eventHandlers: Record 121 | ) { 122 | this.id = nextProxyId++; 123 | this.worker = worker; 124 | 125 | const sendEvent = (data: any): void => { 126 | this.worker.postMessage({ 127 | type: 'event', 128 | id: this.id, 129 | data, 130 | }); 131 | }; 132 | 133 | // Register an ID 134 | worker.postMessage({ 135 | type: 'makeProxy', 136 | id: this.id, 137 | }); 138 | 139 | for (const [eventName, handler] of Object.entries(eventHandlers)) { 140 | element.addEventListener(eventName, (event) => { 141 | handler(event as any, sendEvent); 142 | }); 143 | } 144 | 145 | function sendSize(): void { 146 | sendEvent({ 147 | type: 'resize', 148 | left: 0, 149 | top: 0, 150 | width: innerWidth, 151 | height: innerHeight, 152 | }); 153 | } 154 | 155 | // Really need to use ResizeObserver 156 | window.addEventListener('resize', sendSize); 157 | sendSize(); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/webworker/LoadWorker.ts: -------------------------------------------------------------------------------- 1 | import { Group, Object3DEventMap } from 'three' 2 | import { FBXLoader } from 'three/examples/jsm/Addons.js' 3 | import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js' 4 | import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js' 5 | import { Assets, File, ModelInfo } from '../types' 6 | 7 | let loadedAssets = 0 8 | 9 | const assets: Assets = { 10 | audio: new Map(), 11 | blob: new Map(), 12 | buffer: new Map(), 13 | image: new Map(), 14 | json: new Map(), 15 | model: new Map(), 16 | video: new Map(), 17 | } 18 | 19 | // Loaders 20 | 21 | const draco = new DRACOLoader(); 22 | draco.setDecoderPath('/libs/draco/'); 23 | draco.preload() 24 | 25 | const fbxLoader = new FBXLoader() 26 | 27 | const gltfLoader = new GLTFLoader() 28 | gltfLoader.setDRACOLoader(draco) 29 | 30 | // Load functions 31 | 32 | async function loadBuffer(url: string): Promise { 33 | const response = await fetch(url); 34 | return await response.arrayBuffer(); 35 | } 36 | 37 | async function loadBlob(url: string): Promise { 38 | const response = await fetch(url); 39 | return await response.blob(); 40 | } 41 | 42 | async function loadFBX(url: string): Promise { 43 | return new Promise((resolve) => { 44 | fbxLoader.loadAsync(url) 45 | .then((value: Group) => { 46 | resolve({ 47 | animations: value.animations.map(animation => animation.toJSON(animation)), 48 | scene: value.toJSON(), 49 | }) 50 | }) 51 | .catch((reason: any) => { 52 | console.log('FBX Error:') 53 | console.log(reason) 54 | }) 55 | }) 56 | } 57 | 58 | async function loadGLTF(url: string): Promise { 59 | return new Promise((resolve) => { 60 | gltfLoader.loadAsync(url) 61 | .then((value: GLTF) => { 62 | resolve({ 63 | animations: value.animations.map(animation => animation.toJSON(animation)), 64 | cameras: value.cameras.map(camera => camera.toJSON()), 65 | scene: value.scene.toJSON(), 66 | }) 67 | }) 68 | .catch((reason: any) => { 69 | console.log('GLTF Error:') 70 | console.log(reason) 71 | }) 72 | }) 73 | } 74 | 75 | async function loadImage(url: string): Promise { 76 | const response = await fetch(url); 77 | const blob = await response.blob(); 78 | return await createImageBitmap(blob); 79 | } 80 | 81 | async function loadJSON(url: string): Promise { 82 | const response = await fetch(url); 83 | return response.json(); 84 | } 85 | 86 | // Load calls 87 | 88 | function loadStart(assetList: File[]) { 89 | assetList.forEach((item: File) => { 90 | switch (item.type) { 91 | case 'audio': 92 | loadBuffer(item.file).then((value: ArrayBuffer) => { 93 | assets.audio.set(item.name, value) 94 | onLoad(assetList) 95 | }) 96 | break 97 | case 'blob': 98 | loadBlob(item.file).then((value: Blob) => { 99 | assets.blob.set(item.name, value) 100 | onLoad(assetList) 101 | }) 102 | break 103 | case 'buffer': 104 | loadBuffer(item.file).then((value: ArrayBuffer) => { 105 | assets.buffer.set(item.name, value) 106 | onLoad(assetList) 107 | }) 108 | break 109 | case 'fbx': 110 | loadFBX(item.file).then((value: ModelInfo) => { 111 | assets.model.set(item.name, value) 112 | onLoad(assetList) 113 | }) 114 | break 115 | case 'gltf': 116 | loadGLTF(item.file).then((value: ModelInfo) => { 117 | assets.model.set(item.name, value) 118 | onLoad(assetList) 119 | }) 120 | break 121 | case 'image': 122 | loadImage(item.file).then((value: ImageBitmap) => { 123 | assets.image.set(item.name, value) 124 | onLoad(assetList) 125 | }) 126 | break 127 | case 'json': 128 | loadJSON(item.file).then((value: any) => { 129 | assets.json.set(item.name, value) 130 | onLoad(assetList) 131 | }) 132 | break 133 | case 'video': 134 | loadBlob(item.file).then((value: Blob) => { 135 | assets.video.set(item.name, value) 136 | onLoad(assetList) 137 | }) 138 | break 139 | } 140 | }) 141 | } 142 | 143 | function onLoad(assetList: File[]) { 144 | loadedAssets++ 145 | if (loadedAssets >= assetList.length) loadComplete() 146 | } 147 | 148 | function loadComplete() { 149 | self.postMessage({ type: 'loadComplete', data: assets }) 150 | } 151 | 152 | // Worker 153 | 154 | self.onmessage = (event) => { 155 | switch (event.data.type) { 156 | case 'loadStart': 157 | loadStart(event.data.data) 158 | break; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/webworker/ProxyManager.ts: -------------------------------------------------------------------------------- 1 | import { EventDispatcher } from 'three'; 2 | 3 | function noop(): void {} 4 | 5 | interface SizeData { 6 | left: number; 7 | top: number; 8 | width: number; 9 | height: number; 10 | } 11 | 12 | interface EventData extends SizeData { 13 | type: string; 14 | id?: number; 15 | data?: any; 16 | preventDefault?: () => void; 17 | stopPropagation?: () => void; 18 | } 19 | 20 | export class ElementProxyReceiver extends EventDispatcher { 21 | style: Record = {}; 22 | left: number = 0; 23 | top: number = 0; 24 | width: number = 0; 25 | height: number = 0; 26 | ownerDocument: any = undefined; 27 | 28 | constructor() { 29 | super() 30 | this.ownerDocument = this 31 | } 32 | 33 | get clientWidth(): number { 34 | return this.width; 35 | } 36 | 37 | set clientWidth(value: number) { 38 | this.width = value; 39 | } 40 | 41 | get clientHeight(): number { 42 | return this.height; 43 | } 44 | 45 | set clientHeight(value: number) { 46 | this.height = value; 47 | } 48 | 49 | // OrbitControls call these as of r132. Implementing as no-ops 50 | setPointerCapture(): void {} 51 | releasePointerCapture(): void {} 52 | 53 | getBoundingClientRect(): DOMRect { 54 | return { 55 | x: this.left, 56 | y: this.top, 57 | left: this.left, 58 | top: this.top, 59 | width: this.width, 60 | height: this.height, 61 | right: this.left + this.width, 62 | bottom: this.top + this.height, 63 | toJSON: () => ({}) // Satisfies the DOMRect interface 64 | }; 65 | } 66 | 67 | handleEvent(data: EventData): void { 68 | if (data.type === 'size') { 69 | this.left = data.left; 70 | this.top = data.top; 71 | this.width = data.width; 72 | this.height = data.height; 73 | return; 74 | } 75 | 76 | // Extend event data to include preventDefault and stopPropagation as no-ops 77 | data.preventDefault = noop; 78 | data.stopPropagation = noop; 79 | // @ts-ignore 80 | this.dispatchEvent(data); 81 | } 82 | 83 | focus(): void { 84 | // No-op 85 | } 86 | 87 | getRootNode(): any { 88 | return this 89 | } 90 | } 91 | 92 | export class ProxyManager { 93 | targets: Record = {}; 94 | 95 | constructor() { 96 | this.handleEvent = this.handleEvent.bind(this); 97 | } 98 | 99 | makeProxy(data: { id: number }): void { 100 | const { id } = data; 101 | const proxy = new ElementProxyReceiver(); 102 | this.targets[id] = proxy; 103 | } 104 | 105 | getProxy(id: number): ElementProxyReceiver { 106 | return this.targets[id]; 107 | } 108 | 109 | handleEvent(data: { id: number; data: EventData }): void { 110 | this.targets[data.id]?.handleEvent(data.data); 111 | } 112 | } -------------------------------------------------------------------------------- /src/webworker/workers.ts: -------------------------------------------------------------------------------- 1 | import { dispatcher, Events } from '../global/constants' 2 | import Settings from '../global/settings' 3 | 4 | export default class Workers { 5 | static canvas: Worker | null 6 | static loader: Worker | null 7 | 8 | static init() { 9 | // Canvas 10 | 11 | if (Settings.supportOffScreenCanvas) { 12 | this.canvas = new Worker(new URL('./CanvasWorker.ts', import.meta.url), { type: 'module' }) 13 | } 14 | 15 | // Loader 16 | 17 | this.loader = new Worker(new URL('./LoadWorker.ts', import.meta.url), { type: 'module' }) 18 | this.loader.onmessage = (event: MessageEvent) => { 19 | if (event.data.type === 'loadComplete') { 20 | const assets = event.data.data 21 | dispatcher.dispatchEvent({ type: Events.LoadComplete, value: assets }) 22 | this.canvas?.postMessage({ type: 'loadComplete', data: assets }) 23 | this.loader?.terminate() 24 | this.loader = null 25 | } 26 | } 27 | 28 | const loadStart = (event: any) => { 29 | dispatcher.removeEventListener(Events.LoadStart, loadStart) 30 | this.loader?.postMessage({ type: 'loadStart', data: event.value }) 31 | } 32 | dispatcher.addEventListener(Events.LoadStart, loadStart) 33 | } 34 | 35 | static dispose() { 36 | this.canvas?.terminate() 37 | this.canvas = null 38 | this.loader?.terminate() 39 | this.loader = null 40 | } 41 | } -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 4 | "target": "ES2020", 5 | "useDefineForClassFields": true, 6 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 7 | "module": "ESNext", 8 | "skipLibCheck": true, 9 | 10 | /* Bundler mode */ 11 | "moduleResolution": "Bundler", 12 | "allowImportingTsExtensions": true, 13 | "isolatedModules": true, 14 | "moduleDetection": "force", 15 | "noEmit": true, 16 | "jsx": "react-jsx", 17 | 18 | /* Linting */ 19 | "strict": true, 20 | "noUnusedLocals": true, 21 | "noUnusedParameters": true, 22 | "noFallthroughCasesInSwitch": true, 23 | "noUncheckedSideEffectImports": true 24 | }, 25 | "include": ["src"] 26 | } 27 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.app.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 4 | "target": "ES2022", 5 | "lib": ["ES2023"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "Bundler", 11 | "allowImportingTsExtensions": true, 12 | "isolatedModules": true, 13 | "moduleDetection": "force", 14 | "noEmit": true, 15 | 16 | /* Linting */ 17 | "strict": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noFallthroughCasesInSwitch": true, 21 | "noUncheckedSideEffectImports": true 22 | }, 23 | "include": ["vite.config.ts"] 24 | } 25 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vite.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | --------------------------------------------------------------------------------