lunchboxjs 0.1.4006 → 0.1.4010

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -111,6 +111,7 @@
111
111
  dpr: Number,
112
112
  ortho: Boolean,
113
113
  orthographic: Boolean,
114
+ rendererArguments: Object,
114
115
  rendererProperties: Object,
115
116
  shadow: [Boolean, Object],
116
117
  transparent: Boolean,
@@ -140,12 +141,11 @@
140
141
  if (!renderer) {
141
142
  // build renderer args
142
143
  const rendererArgs = {
144
+ alpha: props.transparent,
143
145
  antialias: true,
144
146
  canvas: canvas.value.domElement,
147
+ ...(props.rendererArguments ?? {}),
145
148
  };
146
- if (props.transparent) {
147
- rendererArgs.alpha = true;
148
- }
149
149
  // create new renderer
150
150
  ensureRenderer.value = createNode({
151
151
  type: 'WebGLRenderer',
@@ -183,7 +183,6 @@
183
183
  // the user has initialized the renderer, so anything depending
184
184
  // on the renderer can execute
185
185
  rendererReady.value = true;
186
- return;
187
186
  }
188
187
  // CAMERA
189
188
  // ====================
@@ -217,14 +216,17 @@
217
216
  else {
218
217
  cameraReady.value = true;
219
218
  }
219
+ if (!camera.instance) {
220
+ throw new Error('Error creating camera.');
221
+ }
220
222
  // move camera if needed
221
223
  if (camera && props.cameraPosition) {
222
- camera.instance?.position.set(...props.cameraPosition);
224
+ camera.instance.position.set(...props.cameraPosition);
223
225
  }
224
226
  // angle camera if needed
225
227
  if (camera && (props.cameraLookAt || props.cameraLook)) {
226
228
  const source = (props.cameraLookAt || props.cameraLook);
227
- camera.instance?.lookAt(...source);
229
+ camera.instance.lookAt(...source);
228
230
  }
229
231
  // SCENE
230
232
  // ====================
@@ -247,11 +249,23 @@
247
249
  else {
248
250
  throw new Error('missing renderer');
249
251
  }
252
+ // CALLBACK PREP
253
+ // ====================
254
+ const app = vue.getCurrentInstance().appContext.app;
255
+ // START
256
+ // ====================
257
+ for (let startCallback of startCallbacks) {
258
+ startCallback({
259
+ app,
260
+ camera: camera.instance,
261
+ renderer: renderer.instance,
262
+ scene: scene.instance,
263
+ });
264
+ }
250
265
  // KICK UPDATE
251
266
  // ====================
252
- // console.log(scene)
253
267
  update({
254
- app: vue.getCurrentInstance().appContext.app,
268
+ app,
255
269
  camera: camera.instance,
256
270
  renderer: renderer.instance,
257
271
  scene: scene.instance,
@@ -628,7 +642,6 @@
628
642
  // register click, pointerdown, pointerup
629
643
  if (key === 'onClick' || key === 'onPointerDown' || key === 'onPointerUp') {
630
644
  const stop = vue.watch(() => inputActive.value, (isDown) => {
631
- console.log(isDown, currentIntersections);
632
645
  const idx = currentIntersections
633
646
  .map((v) => v.element)
634
647
  .findIndex((v) => v.instance &&
@@ -1261,6 +1274,16 @@
1261
1274
  const rootNode = new MiniDom.RendererRootNode();
1262
1275
  rootNode.minidomType = 'RootNode';
1263
1276
 
1277
+ const startCallbacks = [];
1278
+ const onStart = (cb, index = Infinity) => {
1279
+ if (index === Infinity) {
1280
+ startCallbacks.push(cb);
1281
+ }
1282
+ else {
1283
+ startCallbacks.splice(index, 0, cb);
1284
+ }
1285
+ };
1286
+
1264
1287
  let frameID;
1265
1288
  const beforeRender = [];
1266
1289
  const afterRender = [];
@@ -1683,9 +1706,51 @@
1683
1706
  inputActive,
1684
1707
  mousePos,
1685
1708
  };
1709
+ /** The current camera. Often easier to use `useCamera` instead of this. */
1686
1710
  const camera = vue.computed(() => ensuredCamera.value?.instance ?? null);
1711
+ /** Run a function using the current camera when it's present. */
1712
+ function useCamera(callback, once = true) {
1713
+ let destroy;
1714
+ destroy = vue.watch(camera, (newVal) => {
1715
+ if (!newVal)
1716
+ return;
1717
+ // TODO: better fix than `any`?
1718
+ callback(newVal);
1719
+ if (once) {
1720
+ destroy?.();
1721
+ }
1722
+ }, { immediate: true });
1723
+ }
1724
+ /** The current renderer. Often easier to use `useRenderer` instead of this. */
1687
1725
  const renderer = vue.computed(() => ensureRenderer.value?.instance ?? null);
1726
+ /** Run a function using the current renderer when it's present. */
1727
+ function useRenderer(callback, once = true) {
1728
+ let destroy;
1729
+ destroy = vue.watch(renderer, (newVal) => {
1730
+ if (!newVal)
1731
+ return;
1732
+ // TODO: better fix than `any`?
1733
+ callback(newVal);
1734
+ if (once) {
1735
+ destroy?.();
1736
+ }
1737
+ }, { immediate: true });
1738
+ }
1739
+ /** The current scene. Often easier to use `useScene` instead of this. */
1688
1740
  const scene = vue.computed(() => ensuredScene.value.instance);
1741
+ /** Run a function using the current scene when it's present. */
1742
+ function useScene(callback, once = true) {
1743
+ let destroy;
1744
+ destroy = vue.watch(scene, (newVal) => {
1745
+ if (!newVal)
1746
+ return;
1747
+ // TODO: better fix than `any`?
1748
+ callback(newVal);
1749
+ if (once) {
1750
+ destroy?.();
1751
+ }
1752
+ }, { immediate: true });
1753
+ }
1689
1754
  // CUSTOM RENDER SUPPORT
1690
1755
  // ====================
1691
1756
  let app = null;
@@ -1761,9 +1826,13 @@
1761
1826
  exports.offBeforeRender = offBeforeRender;
1762
1827
  exports.onAfterRender = onAfterRender;
1763
1828
  exports.onBeforeRender = onBeforeRender;
1829
+ exports.onStart = onStart;
1764
1830
  exports.renderer = renderer;
1765
1831
  exports.scene = scene;
1766
1832
  exports.setCustomRender = setCustomRender;
1833
+ exports.useCamera = useCamera;
1834
+ exports.useRenderer = useRenderer;
1835
+ exports.useScene = useScene;
1767
1836
 
1768
1837
  Object.defineProperty(exports, '__esModule', { value: true });
1769
1838
 
@@ -1 +1 @@
1
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("vue"),require("three"),require("lodash")):"function"==typeof define&&define.amd?define(["exports","vue","three","lodash"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).LunchboxRenderer={},e.vue,e.three,e.lodash)}(this,(function(e,t,n,r){"use strict";function o(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(n){if("default"!==n){var r=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,r.get?r:{enumerable:!0,get:function(){return e[n]}})}})),t.default=e,Object.freeze(t)}var a=o(n);const s=[],i=(e,n)=>{const r=K.value?.instance,o=_.value.instance,a=$.value;if(!r?.domElement||!o||!a)return;const s=(e=e??window.innerWidth)/(n=n??window.innerHeight);if("perspectivecamera"===a.type?.toLowerCase()){const e=a.instance;e.aspect=s,e.updateProjectionMatrix()}else if("orthographiccamera"===a.type?.toLowerCase()){const t=a.instance,r=n/e;t.top=10*r,t.bottom=10*-r,t.right=10,t.left=-10,t.updateProjectionMatrix()}else console.log("TODO: non-ortho or perspective camera");r.setSize(e,n),o&&a.instance&&r.render(t.toRaw(o),t.toRaw(a.instance))},c=e=>({position:e,top:0,right:0,bottom:0,left:0,width:"100%",height:"100%"}),d={name:"Lunchbox",props:{background:String,cameraArgs:Array,cameraLook:Array,cameraLookAt:Array,cameraPosition:Array,dpr:Number,ortho:Boolean,orthographic:Boolean,rendererProperties:Object,shadow:[Boolean,Object],transparent:Boolean},setup(e,o){const a=t.ref(),s=t.ref(!0),d=t.ref(e.dpr??-1),u=t.ref();let l,p,m;return t.onMounted((()=>{if(!a.value)throw new Error("missing canvas");if(l=T(["WebGLRenderer"]),l)return s.value=!1,void(I.value=!0);{const t={antialias:!0,canvas:a.value.domElement};e.transparent&&(t.alpha=!0),K.value=g({type:"WebGLRenderer",uuid:U,props:{args:[t]}}),I.value=!0;const n=K,o={shadow:e.shadow};n.value.instance&&o?.shadow&&(n.value.instance.shadowMap.enabled=!0,"object"==typeof o.shadow&&(n.value.instance.shadowMap.type=o.shadow.type)),e.rendererProperties&&Object.keys(e.rendererProperties).forEach((t=>{r.set(n.value,t,e.rendererProperties[t])})),l=n.value}if(p=T(["PerspectiveCamera","OrthographicCamera"]),p?D.value=!0:(e.ortho||e.orthographic?$.value=g({props:{args:e.cameraArgs??[]},type:"OrthographicCamera",uuid:F}):$.value=g({props:{args:e.cameraArgs??[45,.5625,1,1e3]},type:"PerspectiveCamera",uuid:F}),D.value=!0,p=$.value),p&&e.cameraPosition&&p.instance?.position.set(...e.cameraPosition),p&&(e.cameraLookAt||e.cameraLook)){const t=e.cameraLookAt||e.cameraLook;p.instance?.lookAt(...t)}if(m=_.value,m&&m.instance&&e.background&&(m.instance.background=new n.Color(e.background)),-1===d.value&&(d.value=window.devicePixelRatio),!l?.instance)throw new Error("missing renderer");l.instance.setPixelRatio(d.value),he.dpr.value=d.value,((e,t,n)=>{const r=e.value?.domElement;if(!r)throw new Error("missing container");i();const o=new ResizeObserver((([e])=>{i()}));r&&o.observe(r),n((()=>{t&&o.unobserve(t)}))})(u,l.instance.domElement,t.onBeforeUnmount),ae({app:t.getCurrentInstance().appContext.app,camera:p.instance,renderer:l.instance,scene:m.instance})})),t.onBeforeUnmount((()=>{ie()})),()=>[o.slots.default?.()??null,t.h("div",{style:c("absolute"),ref:u},[s.value?t.h("canvas",{style:c("fixed"),class:"lunchbox-canvas",ref:a}):null])]}},u=["mesh","instancedMesh","scene","sprite","object3D","instancedBufferGeometry","bufferGeometry","boxBufferGeometry","circleBufferGeometry","coneBufferGeometry","cylinderBufferGeometry","dodecahedronBufferGeometry","extrudeBufferGeometry","icosahedronBufferGeometry","latheBufferGeometry","octahedronBufferGeometry","parametricBufferGeometry","planeBufferGeometry","polyhedronBufferGeometry","ringBufferGeometry","shapeBufferGeometry","sphereBufferGeometry","tetrahedronBufferGeometry","textBufferGeometry","torusBufferGeometry","torusKnotBufferGeometry","tubeBufferGeometry","wireframeGeometry","parametricGeometry","tetrahedronGeometry","octahedronGeometry","icosahedronGeometry","dodecahedronGeometry","polyhedronGeometry","tubeGeometry","torusKnotGeometry","torusGeometry","sphereGeometry","ringGeometry","planeGeometry","latheGeometry","shapeGeometry","extrudeGeometry","edgesGeometry","coneGeometry","cylinderGeometry","circleGeometry","boxGeometry","material","shadowMaterial","spriteMaterial","rawShaderMaterial","shaderMaterial","pointsMaterial","meshPhysicalMaterial","meshStandardMaterial","meshPhongMaterial","meshToonMaterial","meshNormalMaterial","meshLambertMaterial","meshDepthMaterial","meshDistanceMaterial","meshBasicMaterial","meshMatcapMaterial","lineDashedMaterial","lineBasicMaterial","light","spotLightShadow","spotLight","pointLight","rectAreaLight","hemisphereLight","directionalLightShadow","directionalLight","ambientLight","lightShadow","ambientLightProbe","hemisphereLightProbe","lightProbe","texture","videoTexture","dataTexture","dataTexture3D","compressedTexture","cubeTexture","canvasTexture","depthTexture","textureLoader","group","catmullRomCurve3","points","cameraHelper","camera","perspectiveCamera","orthographicCamera","cubeCamera","arrayCamera","webGLRenderer"],l={},p=["canvas","div","LunchboxWrapper"];u.map((e=>t.defineComponent({inheritAttrs:!1,name:e,setup:(n,r)=>()=>t.h(e,r.attrs,r.slots?.default?.()||[])}))).reduce(((e,t)=>(e[t.name]=t,e)));const m={...u,Lunchbox:d};const h=e=>e?.$el&&e?.$el?.hasOwnProperty?.("instance"),f=e=>{if("domMeta"===e?.metaType)return!0;const t="string"==typeof e?e:e?.type;return p.includes(t??"")},y=e=>"standardMeta"===e?.metaType,v=e=>e.isLunchboxRootNode;function g(e={},t={}){const n={attached:e.attached??[],attachedArray:e.attachedArray??{},instance:e.instance??null},r=new Q.RendererStandardNode({...e,...n,metaType:"standardMeta"});return!r.type||v(r)||r.instance||(r.instance=function(e){if(!e.type)return null;const t=e.type[0].toUpperCase()+e.type.slice(1),n=l[e.type]||a[t];if(!n)throw`${t} is not part of the THREE namespace! Did you forget to extend? import {extend} from 'lunchbox'; extend({app, YourComponent, ...})`;const r=(e.props.args??[]).map((t=>function({node:e,prop:t}){const n="string"==typeof t&&t.startsWith("$attachedArray"),r=function({node:e,prop:t}){if("string"==typeof t&&t.startsWith("$attachedArray"))return e.attachedArray[t.replace("$attachedArray.","")];if("string"==typeof t&&t.startsWith("$attached"))return e.attached[t.replace("$attached.","")];return t}({node:e,prop:t});return Array.isArray(r)&&n?r:[r]}({node:e,prop:t})));let o=[];r.forEach((e=>{o=o.concat(e)}));return new n(...o)}({...r,props:{...r.props,...t}})),"scene"===r.type&&(_.value=r),r}const b=[],x=t.ref(!1);function R({node:e,key:n,value:r}){var o;if(e.eventListeners[n]||(e.eventListeners[n]=[]),e.eventListenerRemoveFunctions[n]||(e.eventListenerRemoveFunctions[n]=[]),e.eventListeners[n].push(r),A.includes(n)&&(V.value,e.instance&&!b.includes(e)&&(o=e,b.push(o),e.eventListenerRemoveFunctions[n].push((()=>(e=>{const t=b.indexOf(e);-1!==t&&b.splice(t,1)})(e))))),"onClick"===n||"onPointerDown"===n||"onPointerUp"===n){const r=t.watch((()=>x.value),(t=>{console.log(t,M);const r=M.map((e=>e.element)).findIndex((t=>t.instance&&t.instance.uuid===e.instance?.uuid));-1!==r&&((!t||"onClick"!==n&&"onPointerDown"!==n)&&(t||"onPointerUp"!==n)||e.eventListeners[n].forEach((e=>{e({intersection:M[r].intersection})})))}));e.eventListenerRemoveFunctions[n].push(r)}return e}const A=["onClick","onPointerUp","onPointerDown","onPointerOver","onPointerOut","onPointerEnter","onPointerLeave","onPointerMove"];let w,C,E;const L=t.ref({x:1/0,y:1/0});let P=!1;let M=[];const B=()=>{const e=V.value?.instance,t=$.value?.instance;if(!e||!t)return;e.setFromCamera(he.mousePos.value,t);const n=e.intersectObjects(b.map((e=>e.instance)));let r=[],o=[],a=[];r=M.map((e=>e.intersection)),n?.forEach((e=>{const t=M.findIndex((t=>t.intersection.object===e.object));if(-1===t){const t=b.find((t=>t.instance?.uuid===e.object.uuid));t&&o.push({element:t,intersection:e})}else{const t=b.find((t=>t.instance?.uuid===e.object.uuid));t&&a.push({element:t,intersection:e})}const n=r.findIndex((t=>t.object.uuid===e.object.uuid));-1!==n&&r.splice(n,1)}));const s=r.map((e=>({element:b.find((t=>t.instance?.uuid===e.object.uuid)),intersection:e})));o.forEach((({element:e,intersection:t})=>{G({element:e,eventKeys:["onPointerEnter"],intersection:t})})),a.forEach((({element:e,intersection:t})=>{G({element:e,eventKeys:["onPointerOver","onPointerMove"],intersection:t})})),s.forEach((({element:e,intersection:t})=>{G({element:e,eventKeys:["onPointerLeave","onPointerOut"],intersection:t})})),M=[].concat(o,a)},G=({element:e,eventKeys:t,intersection:n})=>{e&&t.forEach((t=>{e.eventListeners[t]&&e.eventListeners[t].forEach((e=>{e({intersection:n})}))}))};function N(t={}){return e.lunchboxTree||(e.lunchboxTree=new Q.RendererRootNode(t)),e.lunchboxTree}function T(e){Array.isArray(e)||(e=[e]);for(let t of e)if(j[t])return j[t];for(let t of e){const e=O[t]||s.find((e=>e.type?.toLowerCase()===t.toLowerCase()));if(e){const n=e;return O[t]=n,n}}return null}e.lunchboxTree=void 0;const O=t.reactive({}),j=t.reactive({});function k(e,n,r={},o=null){Array.isArray(e)||(e=[e]);for(let t of e)O[t]||(O[t]=null),j[t]||(j[t]=null);return t.computed({get(){const t=T(e);if(t)return t;const a=N(),s=g({type:e[0],uuid:n,props:r});return a.addChild(s),O[e[0]]=s,o&&o(s),s},set(e){const t=e.type??"",n=t[0].toUpperCase()+t.slice(1);j[n]=e}})}const F="FALLBACK_CAMERA",S=k(["PerspectiveCamera","OrthographicCamera"],F,{args:[45,.5625,1,1e3]}),D=t.ref(!1),$=t.computed({get:()=>D.value?S.value:null,set(e){const t=e.type??"",n=t[0].toUpperCase()+t.slice(1);j[n]=e}}),U="FALLBACK_RENDERER",W=k(["WebGLRenderer"],U,{}),I=t.ref(!1),K=t.computed({get:()=>I.value?W.value:null,set(e){const t=e.type??"",n=t[0].toUpperCase()+t.slice(1);j[n]=e}}),_=k("Scene","FALLBACK_SCENE"),V=k("Raycaster","AUTO_RAYCASTER",{},(e=>(e=>{if(!e.instance)return;let n=null;n=t.watch((()=>K.value),(e=>{e?.instance&&(P||(w=t=>{const n=(e.instance.domElement.width??1)/he.dpr.value,r=(e.instance.domElement.height??1)/he.dpr.value;L.value.x=t.offsetX/n*2-1,L.value.y=-t.offsetY/r*2+1},C=()=>x.value=!0,E=()=>x.value=!1,e.instance.domElement.addEventListener("mousemove",w),e.instance.domElement.addEventListener("mousedown",C),e.instance.domElement.addEventListener("mouseup",E),se(B),P=!0),n&&n())}),{immediate:!0})})(e))),q=e=>t.defineComponent({inheritAttrs:!1,name:e,render(){return t.h(e,this.$attrs,this.$slots?.default?.()||[])}});var z,H=new Uint8Array(16);function Y(){if(!z&&!(z="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||"undefined"!=typeof msCrypto&&"function"==typeof msCrypto.getRandomValues&&msCrypto.getRandomValues.bind(msCrypto)))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return z(H)}var X=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;function J(e){return"string"==typeof e&&X.test(e)}for(var Q,Z=[],ee=0;ee<256;++ee)Z.push((ee+256).toString(16).substr(1));function te(e,t,n){var r=(e=e||{}).random||(e.rng||Y)();if(r[6]=15&r[6]|64,r[8]=63&r[8]|128,t){n=n||0;for(var o=0;o<16;++o)t[n+o]=r[o];return t}return function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=(Z[e[t+0]]+Z[e[t+1]]+Z[e[t+2]]+Z[e[t+3]]+"-"+Z[e[t+4]]+Z[e[t+5]]+"-"+Z[e[t+6]]+Z[e[t+7]]+"-"+Z[e[t+8]]+Z[e[t+9]]+"-"+Z[e[t+10]]+Z[e[t+11]]+Z[e[t+12]]+Z[e[t+13]]+Z[e[t+14]]+Z[e[t+15]]).toLowerCase();if(!J(n))throw TypeError("Stringified UUID is invalid");return n}(r)}!function(e){e.BaseNode=class{constructor(e={},t){this.parentNode=e?.parentNode??t??null,this.minidomType="MinidomBaseNode",this.uuid=e?.uuid??te(),s.push(this)}uuid;parentNode;get nextSibling(){if(!this.parentNode)return null;const e=this.parentNode.children.findIndex((e=>e.uuid===this.uuid));return-1!==e&&e<this.parentNode.children.length-1?this.parentNode.children[e+1]:null}insertBefore(e,t){e.removeAsChildFromAnyParents(),e.parentNode=this;const n=this.children.findIndex((e=>e.uuid===t?.uuid));-1!==n?this.children.splice(n,0,e):this.children.push(e)}removeChild(e){const t=this.children.findIndex((t=>t?.uuid===e?.uuid));-1!==t&&this.children.splice(t,1)}children=[];addChild(e){return e&&(e.removeAsChildFromAnyParents(),e.parentNode=this,this.insertBefore(e,null)),this}getPath(){const e=[];let t=this;for(;t;)e.unshift(t),t=t.parentNode;return e}drop(){this.parentNode=null,this.removeAsChildFromAnyParents()}walk(e){const t=[this,...this.children],n=[];let r=!0;for(;t.length&&r;){const o=t.shift();if(o){if(n.includes(o))continue;n.push(o),t.push(...o.children.filter((e=>!n.includes(e)))),r=e(o)}else r=!1}}minidomType;removeAsChildFromAnyParents(){s.forEach((e=>e.removeChild(this)))}};class t extends e.BaseNode{constructor(e={},t){super(e,t),this.minidomType="RendererNode",this.eventListeners={},this.eventListenerRemoveFunctions={},this.name=e.name??"",this.metaType=e.metaType??"standardMeta",this.props=e.props??[],this.type=e.type??""}eventListeners;eventListenerRemoveFunctions;name;metaType;props;type;drop(){super.drop(),Object.keys(this.eventListenerRemoveFunctions).forEach((e=>{this.eventListenerRemoveFunctions[e].forEach((e=>e()))}))}}e.RendererBaseNode=t;class n extends e.RendererBaseNode{constructor(e={},t){super(e,t),this.domElement=e.domElement??document.createElement("div")}domElement;isLunchboxRootNode=!0}e.RendererRootNode=n;class r extends e.RendererBaseNode{constructor(e={},t){super(e,t),this.text=e.text??""}text}e.RendererCommentNode=r;class o extends e.RendererBaseNode{constructor(e={},t){super(e,t),this.domElement=e.domElement??document.createElement("div")}domElement}e.RendererDomNode=o;class a extends e.RendererBaseNode{constructor(e={},t){super(e,t),this.text=e.text??""}text}e.RendererTextNode=a;class i extends e.RendererBaseNode{constructor(e={},t){super(e,t),this.attached=e.attached??[],this.attachedArray=e.attachedArray??{},this.instance=e.instance??null}attached;attachedArray;instance}e.RendererStandardNode=i}(Q||(Q={}));let ne;(new Q.RendererRootNode).minidomType="RootNode";const re=[],oe=[],ae=e=>{ne=requestAnimationFrame((()=>ae({app:e.app,renderer:K.value?.instance,scene:_.value.instance,camera:$.value?.instance})));const{app:n,renderer:r,scene:o,camera:a}=e;re.forEach((t=>{t&&t(e)})),r&&o&&a&&(n.customRender?n.customRender(e):r.render(t.toRaw(o),t.toRaw(a))),oe.forEach((t=>{t&&t(e)}))},se=(e,t=1/0)=>{t===1/0?re.push(e):re.splice(t,0,e)},ie=()=>{ne&&cancelAnimationFrame(ne)};const ce={x:"position.x",y:"position.y",z:"position.z"},de=["","parameters"],ue=["args","attach","attachArray","key","onAdded","ref","src"],le=["geometry","material"];function pe(e,t,n,r){const o=r??e.instance,a=t.instance;e.props.attach===n&&(t.attached={[n]:o,...t.attached||{}},a[n]=r??e.instance),e.props.attachArray===n&&(t.attachedArray[e.props.attachArray]||(t.attachedArray[e.props.attachArray]=[]),t.attachedArray[e.props.attachArray].push(o),a[n]=[a[n]])}const me={createElement:(e,t,n,r)=>{const o={type:e};r&&(o.props=r);if(f(e)){const e=function(e={}){const t={domElement:document.createElement(e.type??"")};return new Q.RendererDomNode({...t,...e,metaType:"domMeta"})}(o);return e}const a=g(o);return le.forEach((t=>{e.toLowerCase().endsWith(t)&&(a.props.attach=t)})),a},createText:e=>function(e={}){const t={text:e.text??""};return new Q.RendererTextNode({...e,...t,metaType:"textMeta"})}({text:e}),createComment:e=>function(e={}){const t={text:e.text??""};return new Q.RendererCommentNode({...t,...e,metaType:"commentMeta"})}({text:e}),insert:(e,t,n)=>{let r=t??N();if(r.insertBefore(e,n),"commentMeta"!==e.metaType&&"textMeta"!==e.metaType&&(f(e)&&(f(t)||v(t))&&t.domElement.appendChild(e.domElement),y(e))){let n=r.metaType;if("textMeta"===n||"commentMeta"===n){const e=r.getPath();for(let t=e.length-1;t>=0;t--)if("textMeta"!==e[t].metaType&&"commentMeta"!==e[t].metaType){r=e[t];break}}if("standardMeta"===e.metaType&&"scene"!==e.type&&v(r)){const t=_.value;t.instance&&e&&t.addChild(e),e.instance&&e.instance.isObject3D&&t.instance&&t!==e&&t.instance.add(e.instance)}else y(e)&&e.instance?.isObject3D&&y(r)&&r.instance?.isObject3D&&r.instance?.add?.(e.instance);if(e?.props?.attach&&y(t)&&t?.instance){e.type?.toLowerCase().endsWith("loader")&&e.props.src&&(e.props.attach||e.props.attachArray)?function(e,t){const n=e.instance;if(t.attached=t.attached||{},t.attachedArray=t.attachedArray||{},!e.props.attach)return;if("textureloader"===e.type?.toLowerCase()){const r=n.load(e.props.src);pe(e,t,e.props.attach,r)}else n.load(e.props.src,(n=>{pe(e,t,e.props.attach,n)}),null,(e=>{throw new Error(e)}))}(e,t):pe(e,t,e.props.attach)}e.props?.onAdded&&e.props.onAdded({instance:e.instance})}},nextSibling(e){const t=e.nextSibling;return t||null},parentNode(e){const t=e.parentNode;return t||null},patchProp(e,t,n,o){f(e)?"style"===t?Object.keys(o).forEach((t=>{e.domElement.style[t]=o[t]})):e.domElement.setAttribute(t,o):v(e)||t.startsWith("$")||function({node:e,key:t,value:n}){if((e=>["onClick","onContextMenu","onDoubleClick","onPointerUp","onPointerDown","onPointerOver","onPointerOut","onPointerEnter","onPointerLeave","onPointerMove","onWheel"].includes(e))(t))return R({node:e,key:t,value:n});if(ue.includes(t))return e;if(!y(e))return e;if("string"==typeof n&&n.startsWith("$attached")){const t=n.replace("$attached.","");n=r.get(e.attached,t,null)}const o=e.instance;if(!o)return e;const a=t.replace(/-/g,".");let s,i=ce[a]||a;for(let e=0;e<de.length&&!s;e++){const t=[de[e],i].filter(Boolean).join(".");s=s=r.get(o,t)}if(s&&r.isNumber(n)&&s.setScalar)s.setScalar(n);else if(s&&s.set){const e=Array.isArray(n)?n:[n];o[i].set(...e)}else"function"==typeof s?s.bind(e.instance)(...n):void 0!==r.get(o,i,void 0)?r.set(o,i,""===n||n):console.log(`No property ${i} found on ${o}`);const c=o?.texture?.type||o?.type;if("string"==typeof c){const e=c.toLowerCase();switch(!0){case e.includes("material"):o.needsUpdate=!0;break;case e.includes("camera")&&o.updateProjectionMatrix:o.updateProjectionMatrix()}}}({node:e,key:t,value:o})},remove:e=>{if(!e)return;const t=Object.keys(j),n=[];e.walk((e=>(n.push(e),!0))),n.forEach((e=>{const n=t.find((t=>j[t]?.uuid===e.uuid));if(n&&(j[n]=null),y(e)){e.instance?.removeFromParent?.();const t="scene"!==e.type&&e.instance?.dispose;t&&t.bind(e.instance)(),e.instance=null}e.drop();const r=s.findIndex((t=>t.uuid===e.uuid));-1!==r&&s.splice(r,1)}))},setElementText(){},setText(){}},he={dpr:t.ref(1),inputActive:x,mousePos:L},fe=t.computed((()=>$.value?.instance??null)),ye=t.computed((()=>K.value?.instance??null)),ve=t.computed((()=>_.value.instance));let ge=null,be=null;e.camera=fe,e.clearCustomRender=()=>{ge?ge.clearCustomRender():be=null},e.createApp=e=>{ge=t.createRenderer(me).createApp(e),Object.keys(m).forEach((e=>{ge.component(e,m[e])}));const{mount:n}=ge;return ge.mount=(e,...t)=>{const r=N({domElement:"string"==typeof e?document.querySelector(e):e,isLunchboxRootNode:!0,name:"root",metaType:"rootMeta",type:"root",uuid:"LUNCHBOX_ROOT"});ge.rootNode=r;return n(r,...t)},ge.extend=e=>((({app:e,...t})=>{Object.keys(t).forEach((n=>{e.component(n,q(n)),l[n]=t[n]}))})({app:ge,...e}),ge),ge.setCustomRender=e=>{ge.customRender=e},be&&(ge.setCustomRender(be),be=null),ge.clearCustomRender=()=>{ge.customRender=null},ge},e.find=function(e){return e=t.isRef(e)?e.value:e,y(e)?e?.instance:h(e)?e?.$el?.instance:t.isVNode(e)?e.el?.instance:null},e.globals=he,e.offAfterRender=e=>{if(isFinite(e))oe.splice(e,1);else{const t=oe.findIndex((t=>t==e));oe.splice(t,1)}},e.offBeforeRender=e=>{if(isFinite(e))re.splice(e,1);else{const t=re.findIndex((t=>t==e));re.splice(t,1)}},e.onAfterRender=(e,t=1/0)=>{t===1/0?oe.push(e):oe.splice(t,0,e)},e.onBeforeRender=se,e.renderer=ye,e.scene=ve,e.setCustomRender=e=>{ge?ge.setCustomRender(e):be=e},Object.defineProperty(e,"__esModule",{value:!0})}));
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("vue"),require("three"),require("lodash")):"function"==typeof define&&define.amd?define(["exports","vue","three","lodash"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).LunchboxRenderer={},e.vue,e.three,e.lodash)}(this,(function(e,t,n,r){"use strict";function o(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(n){if("default"!==n){var r=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,r.get?r:{enumerable:!0,get:function(){return e[n]}})}})),t.default=e,Object.freeze(t)}var a=o(n);const s=[],i=(e,n)=>{const r=K.value?.instance,o=_.value.instance,a=$.value;if(!r?.domElement||!o||!a)return;const s=(e=e??window.innerWidth)/(n=n??window.innerHeight);if("perspectivecamera"===a.type?.toLowerCase()){const e=a.instance;e.aspect=s,e.updateProjectionMatrix()}else if("orthographiccamera"===a.type?.toLowerCase()){const t=a.instance,r=n/e;t.top=10*r,t.bottom=10*-r,t.right=10,t.left=-10,t.updateProjectionMatrix()}else console.log("TODO: non-ortho or perspective camera");r.setSize(e,n),o&&a.instance&&r.render(t.toRaw(o),t.toRaw(a.instance))},c=e=>({position:e,top:0,right:0,bottom:0,left:0,width:"100%",height:"100%"}),d={name:"Lunchbox",props:{background:String,cameraArgs:Array,cameraLook:Array,cameraLookAt:Array,cameraPosition:Array,dpr:Number,ortho:Boolean,orthographic:Boolean,rendererArguments:Object,rendererProperties:Object,shadow:[Boolean,Object],transparent:Boolean},setup(e,o){const a=t.ref(),s=t.ref(!0),d=t.ref(e.dpr??-1),u=t.ref();let l,p,m;return t.onMounted((()=>{if(!a.value)throw new Error("missing canvas");if(l=T(["WebGLRenderer"]),l)s.value=!1,I.value=!0;else{const t={alpha:e.transparent,antialias:!0,canvas:a.value.domElement,...e.rendererArguments??{}};K.value=g({type:"WebGLRenderer",uuid:U,props:{args:[t]}}),I.value=!0;const n=K,o={shadow:e.shadow};n.value.instance&&o?.shadow&&(n.value.instance.shadowMap.enabled=!0,"object"==typeof o.shadow&&(n.value.instance.shadowMap.type=o.shadow.type)),e.rendererProperties&&Object.keys(e.rendererProperties).forEach((t=>{r.set(n.value,t,e.rendererProperties[t])})),l=n.value}if(p=T(["PerspectiveCamera","OrthographicCamera"]),p?D.value=!0:(e.ortho||e.orthographic?$.value=g({props:{args:e.cameraArgs??[]},type:"OrthographicCamera",uuid:S}):$.value=g({props:{args:e.cameraArgs??[45,.5625,1,1e3]},type:"PerspectiveCamera",uuid:S}),D.value=!0,p=$.value),!p.instance)throw new Error("Error creating camera.");if(p&&e.cameraPosition&&p.instance.position.set(...e.cameraPosition),p&&(e.cameraLookAt||e.cameraLook)){const t=e.cameraLookAt||e.cameraLook;p.instance.lookAt(...t)}if(m=_.value,m&&m.instance&&e.background&&(m.instance.background=new n.Color(e.background)),-1===d.value&&(d.value=window.devicePixelRatio),!l?.instance)throw new Error("missing renderer");l.instance.setPixelRatio(d.value),fe.dpr.value=d.value,((e,t,n)=>{const r=e.value?.domElement;if(!r)throw new Error("missing container");i();const o=new ResizeObserver((([e])=>{i()}));r&&o.observe(r),n((()=>{t&&o.unobserve(t)}))})(u,l.instance.domElement,t.onBeforeUnmount);const o=t.getCurrentInstance().appContext.app;for(let e of ne)e({app:o,camera:p.instance,renderer:l.instance,scene:m.instance});se({app:o,camera:p.instance,renderer:l.instance,scene:m.instance})})),t.onBeforeUnmount((()=>{ce()})),()=>[o.slots.default?.()??null,t.h("div",{style:c("absolute"),ref:u},[s.value?t.h("canvas",{style:c("fixed"),class:"lunchbox-canvas",ref:a}):null])]}},u=["mesh","instancedMesh","scene","sprite","object3D","instancedBufferGeometry","bufferGeometry","boxBufferGeometry","circleBufferGeometry","coneBufferGeometry","cylinderBufferGeometry","dodecahedronBufferGeometry","extrudeBufferGeometry","icosahedronBufferGeometry","latheBufferGeometry","octahedronBufferGeometry","parametricBufferGeometry","planeBufferGeometry","polyhedronBufferGeometry","ringBufferGeometry","shapeBufferGeometry","sphereBufferGeometry","tetrahedronBufferGeometry","textBufferGeometry","torusBufferGeometry","torusKnotBufferGeometry","tubeBufferGeometry","wireframeGeometry","parametricGeometry","tetrahedronGeometry","octahedronGeometry","icosahedronGeometry","dodecahedronGeometry","polyhedronGeometry","tubeGeometry","torusKnotGeometry","torusGeometry","sphereGeometry","ringGeometry","planeGeometry","latheGeometry","shapeGeometry","extrudeGeometry","edgesGeometry","coneGeometry","cylinderGeometry","circleGeometry","boxGeometry","material","shadowMaterial","spriteMaterial","rawShaderMaterial","shaderMaterial","pointsMaterial","meshPhysicalMaterial","meshStandardMaterial","meshPhongMaterial","meshToonMaterial","meshNormalMaterial","meshLambertMaterial","meshDepthMaterial","meshDistanceMaterial","meshBasicMaterial","meshMatcapMaterial","lineDashedMaterial","lineBasicMaterial","light","spotLightShadow","spotLight","pointLight","rectAreaLight","hemisphereLight","directionalLightShadow","directionalLight","ambientLight","lightShadow","ambientLightProbe","hemisphereLightProbe","lightProbe","texture","videoTexture","dataTexture","dataTexture3D","compressedTexture","cubeTexture","canvasTexture","depthTexture","textureLoader","group","catmullRomCurve3","points","cameraHelper","camera","perspectiveCamera","orthographicCamera","cubeCamera","arrayCamera","webGLRenderer"],l={},p=["canvas","div","LunchboxWrapper"];u.map((e=>t.defineComponent({inheritAttrs:!1,name:e,setup:(n,r)=>()=>t.h(e,r.attrs,r.slots?.default?.()||[])}))).reduce(((e,t)=>(e[t.name]=t,e)));const m={...u,Lunchbox:d};const h=e=>e?.$el&&e?.$el?.hasOwnProperty?.("instance"),f=e=>{if("domMeta"===e?.metaType)return!0;const t="string"==typeof e?e:e?.type;return p.includes(t??"")},y=e=>"standardMeta"===e?.metaType,v=e=>e.isLunchboxRootNode;function g(e={},t={}){const n={attached:e.attached??[],attachedArray:e.attachedArray??{},instance:e.instance??null},r=new Q.RendererStandardNode({...e,...n,metaType:"standardMeta"});return!r.type||v(r)||r.instance||(r.instance=function(e){if(!e.type)return null;const t=e.type[0].toUpperCase()+e.type.slice(1),n=l[e.type]||a[t];if(!n)throw`${t} is not part of the THREE namespace! Did you forget to extend? import {extend} from 'lunchbox'; extend({app, YourComponent, ...})`;const r=(e.props.args??[]).map((t=>function({node:e,prop:t}){const n="string"==typeof t&&t.startsWith("$attachedArray"),r=function({node:e,prop:t}){if("string"==typeof t&&t.startsWith("$attachedArray"))return e.attachedArray[t.replace("$attachedArray.","")];if("string"==typeof t&&t.startsWith("$attached"))return e.attached[t.replace("$attached.","")];return t}({node:e,prop:t});return Array.isArray(r)&&n?r:[r]}({node:e,prop:t})));let o=[];r.forEach((e=>{o=o.concat(e)}));return new n(...o)}({...r,props:{...r.props,...t}})),"scene"===r.type&&(_.value=r),r}const b=[],x=t.ref(!1);function R({node:e,key:n,value:r}){var o;if(e.eventListeners[n]||(e.eventListeners[n]=[]),e.eventListenerRemoveFunctions[n]||(e.eventListenerRemoveFunctions[n]=[]),e.eventListeners[n].push(r),w.includes(n)&&(V.value,e.instance&&!b.includes(e)&&(o=e,b.push(o),e.eventListenerRemoveFunctions[n].push((()=>(e=>{const t=b.indexOf(e);-1!==t&&b.splice(t,1)})(e))))),"onClick"===n||"onPointerDown"===n||"onPointerUp"===n){const r=t.watch((()=>x.value),(t=>{const r=M.map((e=>e.element)).findIndex((t=>t.instance&&t.instance.uuid===e.instance?.uuid));-1!==r&&((!t||"onClick"!==n&&"onPointerDown"!==n)&&(t||"onPointerUp"!==n)||e.eventListeners[n].forEach((e=>{e({intersection:M[r].intersection})})))}));e.eventListenerRemoveFunctions[n].push(r)}return e}const w=["onClick","onPointerUp","onPointerDown","onPointerOver","onPointerOut","onPointerEnter","onPointerLeave","onPointerMove"];let A,C,E;const L=t.ref({x:1/0,y:1/0});let P=!1;let M=[];const B=()=>{const e=V.value?.instance,t=$.value?.instance;if(!e||!t)return;e.setFromCamera(fe.mousePos.value,t);const n=e.intersectObjects(b.map((e=>e.instance)));let r=[],o=[],a=[];r=M.map((e=>e.intersection)),n?.forEach((e=>{const t=M.findIndex((t=>t.intersection.object===e.object));if(-1===t){const t=b.find((t=>t.instance?.uuid===e.object.uuid));t&&o.push({element:t,intersection:e})}else{const t=b.find((t=>t.instance?.uuid===e.object.uuid));t&&a.push({element:t,intersection:e})}const n=r.findIndex((t=>t.object.uuid===e.object.uuid));-1!==n&&r.splice(n,1)}));const s=r.map((e=>({element:b.find((t=>t.instance?.uuid===e.object.uuid)),intersection:e})));o.forEach((({element:e,intersection:t})=>{G({element:e,eventKeys:["onPointerEnter"],intersection:t})})),a.forEach((({element:e,intersection:t})=>{G({element:e,eventKeys:["onPointerOver","onPointerMove"],intersection:t})})),s.forEach((({element:e,intersection:t})=>{G({element:e,eventKeys:["onPointerLeave","onPointerOut"],intersection:t})})),M=[].concat(o,a)},G=({element:e,eventKeys:t,intersection:n})=>{e&&t.forEach((t=>{e.eventListeners[t]&&e.eventListeners[t].forEach((e=>{e({intersection:n})}))}))};function N(t={}){return e.lunchboxTree||(e.lunchboxTree=new Q.RendererRootNode(t)),e.lunchboxTree}function T(e){Array.isArray(e)||(e=[e]);for(let t of e)if(j[t])return j[t];for(let t of e){const e=O[t]||s.find((e=>e.type?.toLowerCase()===t.toLowerCase()));if(e){const n=e;return O[t]=n,n}}return null}e.lunchboxTree=void 0;const O=t.reactive({}),j=t.reactive({});function k(e,n,r={},o=null){Array.isArray(e)||(e=[e]);for(let t of e)O[t]||(O[t]=null),j[t]||(j[t]=null);return t.computed({get(){const t=T(e);if(t)return t;const a=N(),s=g({type:e[0],uuid:n,props:r});return a.addChild(s),O[e[0]]=s,o&&o(s),s},set(e){const t=e.type??"",n=t[0].toUpperCase()+t.slice(1);j[n]=e}})}const S="FALLBACK_CAMERA",F=k(["PerspectiveCamera","OrthographicCamera"],S,{args:[45,.5625,1,1e3]}),D=t.ref(!1),$=t.computed({get:()=>D.value?F.value:null,set(e){const t=e.type??"",n=t[0].toUpperCase()+t.slice(1);j[n]=e}}),U="FALLBACK_RENDERER",W=k(["WebGLRenderer"],U,{}),I=t.ref(!1),K=t.computed({get:()=>I.value?W.value:null,set(e){const t=e.type??"",n=t[0].toUpperCase()+t.slice(1);j[n]=e}}),_=k("Scene","FALLBACK_SCENE"),V=k("Raycaster","AUTO_RAYCASTER",{},(e=>(e=>{if(!e.instance)return;let n=null;n=t.watch((()=>K.value),(e=>{e?.instance&&(P||(A=t=>{const n=(e.instance.domElement.width??1)/fe.dpr.value,r=(e.instance.domElement.height??1)/fe.dpr.value;L.value.x=t.offsetX/n*2-1,L.value.y=-t.offsetY/r*2+1},C=()=>x.value=!0,E=()=>x.value=!1,e.instance.domElement.addEventListener("mousemove",A),e.instance.domElement.addEventListener("mousedown",C),e.instance.domElement.addEventListener("mouseup",E),ie(B),P=!0),n&&n())}),{immediate:!0})})(e))),q=e=>t.defineComponent({inheritAttrs:!1,name:e,render(){return t.h(e,this.$attrs,this.$slots?.default?.()||[])}});var z,H=new Uint8Array(16);function Y(){if(!z&&!(z="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||"undefined"!=typeof msCrypto&&"function"==typeof msCrypto.getRandomValues&&msCrypto.getRandomValues.bind(msCrypto)))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return z(H)}var X=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;function J(e){return"string"==typeof e&&X.test(e)}for(var Q,Z=[],ee=0;ee<256;++ee)Z.push((ee+256).toString(16).substr(1));function te(e,t,n){var r=(e=e||{}).random||(e.rng||Y)();if(r[6]=15&r[6]|64,r[8]=63&r[8]|128,t){n=n||0;for(var o=0;o<16;++o)t[n+o]=r[o];return t}return function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=(Z[e[t+0]]+Z[e[t+1]]+Z[e[t+2]]+Z[e[t+3]]+"-"+Z[e[t+4]]+Z[e[t+5]]+"-"+Z[e[t+6]]+Z[e[t+7]]+"-"+Z[e[t+8]]+Z[e[t+9]]+"-"+Z[e[t+10]]+Z[e[t+11]]+Z[e[t+12]]+Z[e[t+13]]+Z[e[t+14]]+Z[e[t+15]]).toLowerCase();if(!J(n))throw TypeError("Stringified UUID is invalid");return n}(r)}!function(e){e.BaseNode=class{constructor(e={},t){this.parentNode=e?.parentNode??t??null,this.minidomType="MinidomBaseNode",this.uuid=e?.uuid??te(),s.push(this)}uuid;parentNode;get nextSibling(){if(!this.parentNode)return null;const e=this.parentNode.children.findIndex((e=>e.uuid===this.uuid));return-1!==e&&e<this.parentNode.children.length-1?this.parentNode.children[e+1]:null}insertBefore(e,t){e.removeAsChildFromAnyParents(),e.parentNode=this;const n=this.children.findIndex((e=>e.uuid===t?.uuid));-1!==n?this.children.splice(n,0,e):this.children.push(e)}removeChild(e){const t=this.children.findIndex((t=>t?.uuid===e?.uuid));-1!==t&&this.children.splice(t,1)}children=[];addChild(e){return e&&(e.removeAsChildFromAnyParents(),e.parentNode=this,this.insertBefore(e,null)),this}getPath(){const e=[];let t=this;for(;t;)e.unshift(t),t=t.parentNode;return e}drop(){this.parentNode=null,this.removeAsChildFromAnyParents()}walk(e){const t=[this,...this.children],n=[];let r=!0;for(;t.length&&r;){const o=t.shift();if(o){if(n.includes(o))continue;n.push(o),t.push(...o.children.filter((e=>!n.includes(e)))),r=e(o)}else r=!1}}minidomType;removeAsChildFromAnyParents(){s.forEach((e=>e.removeChild(this)))}};class t extends e.BaseNode{constructor(e={},t){super(e,t),this.minidomType="RendererNode",this.eventListeners={},this.eventListenerRemoveFunctions={},this.name=e.name??"",this.metaType=e.metaType??"standardMeta",this.props=e.props??[],this.type=e.type??""}eventListeners;eventListenerRemoveFunctions;name;metaType;props;type;drop(){super.drop(),Object.keys(this.eventListenerRemoveFunctions).forEach((e=>{this.eventListenerRemoveFunctions[e].forEach((e=>e()))}))}}e.RendererBaseNode=t;class n extends e.RendererBaseNode{constructor(e={},t){super(e,t),this.domElement=e.domElement??document.createElement("div")}domElement;isLunchboxRootNode=!0}e.RendererRootNode=n;class r extends e.RendererBaseNode{constructor(e={},t){super(e,t),this.text=e.text??""}text}e.RendererCommentNode=r;class o extends e.RendererBaseNode{constructor(e={},t){super(e,t),this.domElement=e.domElement??document.createElement("div")}domElement}e.RendererDomNode=o;class a extends e.RendererBaseNode{constructor(e={},t){super(e,t),this.text=e.text??""}text}e.RendererTextNode=a;class i extends e.RendererBaseNode{constructor(e={},t){super(e,t),this.attached=e.attached??[],this.attachedArray=e.attachedArray??{},this.instance=e.instance??null}attached;attachedArray;instance}e.RendererStandardNode=i}(Q||(Q={}));(new Q.RendererRootNode).minidomType="RootNode";const ne=[];let re;const oe=[],ae=[],se=e=>{re=requestAnimationFrame((()=>se({app:e.app,renderer:K.value?.instance,scene:_.value.instance,camera:$.value?.instance})));const{app:n,renderer:r,scene:o,camera:a}=e;oe.forEach((t=>{t&&t(e)})),r&&o&&a&&(n.customRender?n.customRender(e):r.render(t.toRaw(o),t.toRaw(a))),ae.forEach((t=>{t&&t(e)}))},ie=(e,t=1/0)=>{t===1/0?oe.push(e):oe.splice(t,0,e)},ce=()=>{re&&cancelAnimationFrame(re)};const de={x:"position.x",y:"position.y",z:"position.z"},ue=["","parameters"],le=["args","attach","attachArray","key","onAdded","ref","src"],pe=["geometry","material"];function me(e,t,n,r){const o=r??e.instance,a=t.instance;e.props.attach===n&&(t.attached={[n]:o,...t.attached||{}},a[n]=r??e.instance),e.props.attachArray===n&&(t.attachedArray[e.props.attachArray]||(t.attachedArray[e.props.attachArray]=[]),t.attachedArray[e.props.attachArray].push(o),a[n]=[a[n]])}const he={createElement:(e,t,n,r)=>{const o={type:e};r&&(o.props=r);if(f(e)){const e=function(e={}){const t={domElement:document.createElement(e.type??"")};return new Q.RendererDomNode({...t,...e,metaType:"domMeta"})}(o);return e}const a=g(o);return pe.forEach((t=>{e.toLowerCase().endsWith(t)&&(a.props.attach=t)})),a},createText:e=>function(e={}){const t={text:e.text??""};return new Q.RendererTextNode({...e,...t,metaType:"textMeta"})}({text:e}),createComment:e=>function(e={}){const t={text:e.text??""};return new Q.RendererCommentNode({...t,...e,metaType:"commentMeta"})}({text:e}),insert:(e,t,n)=>{let r=t??N();if(r.insertBefore(e,n),"commentMeta"!==e.metaType&&"textMeta"!==e.metaType&&(f(e)&&(f(t)||v(t))&&t.domElement.appendChild(e.domElement),y(e))){let n=r.metaType;if("textMeta"===n||"commentMeta"===n){const e=r.getPath();for(let t=e.length-1;t>=0;t--)if("textMeta"!==e[t].metaType&&"commentMeta"!==e[t].metaType){r=e[t];break}}if("standardMeta"===e.metaType&&"scene"!==e.type&&v(r)){const t=_.value;t.instance&&e&&t.addChild(e),e.instance&&e.instance.isObject3D&&t.instance&&t!==e&&t.instance.add(e.instance)}else y(e)&&e.instance?.isObject3D&&y(r)&&r.instance?.isObject3D&&r.instance?.add?.(e.instance);if(e?.props?.attach&&y(t)&&t?.instance){e.type?.toLowerCase().endsWith("loader")&&e.props.src&&(e.props.attach||e.props.attachArray)?function(e,t){const n=e.instance;if(t.attached=t.attached||{},t.attachedArray=t.attachedArray||{},!e.props.attach)return;if("textureloader"===e.type?.toLowerCase()){const r=n.load(e.props.src);me(e,t,e.props.attach,r)}else n.load(e.props.src,(n=>{me(e,t,e.props.attach,n)}),null,(e=>{throw new Error(e)}))}(e,t):me(e,t,e.props.attach)}e.props?.onAdded&&e.props.onAdded({instance:e.instance})}},nextSibling(e){const t=e.nextSibling;return t||null},parentNode(e){const t=e.parentNode;return t||null},patchProp(e,t,n,o){f(e)?"style"===t?Object.keys(o).forEach((t=>{e.domElement.style[t]=o[t]})):e.domElement.setAttribute(t,o):v(e)||t.startsWith("$")||function({node:e,key:t,value:n}){if((e=>["onClick","onContextMenu","onDoubleClick","onPointerUp","onPointerDown","onPointerOver","onPointerOut","onPointerEnter","onPointerLeave","onPointerMove","onWheel"].includes(e))(t))return R({node:e,key:t,value:n});if(le.includes(t))return e;if(!y(e))return e;if("string"==typeof n&&n.startsWith("$attached")){const t=n.replace("$attached.","");n=r.get(e.attached,t,null)}const o=e.instance;if(!o)return e;const a=t.replace(/-/g,".");let s,i=de[a]||a;for(let e=0;e<ue.length&&!s;e++){const t=[ue[e],i].filter(Boolean).join(".");s=s=r.get(o,t)}if(s&&r.isNumber(n)&&s.setScalar)s.setScalar(n);else if(s&&s.set){const e=Array.isArray(n)?n:[n];o[i].set(...e)}else"function"==typeof s?s.bind(e.instance)(...n):void 0!==r.get(o,i,void 0)?r.set(o,i,""===n||n):console.log(`No property ${i} found on ${o}`);const c=o?.texture?.type||o?.type;if("string"==typeof c){const e=c.toLowerCase();switch(!0){case e.includes("material"):o.needsUpdate=!0;break;case e.includes("camera")&&o.updateProjectionMatrix:o.updateProjectionMatrix()}}}({node:e,key:t,value:o})},remove:e=>{if(!e)return;const t=Object.keys(j),n=[];e.walk((e=>(n.push(e),!0))),n.forEach((e=>{const n=t.find((t=>j[t]?.uuid===e.uuid));if(n&&(j[n]=null),y(e)){e.instance?.removeFromParent?.();const t="scene"!==e.type&&e.instance?.dispose;t&&t.bind(e.instance)(),e.instance=null}e.drop();const r=s.findIndex((t=>t.uuid===e.uuid));-1!==r&&s.splice(r,1)}))},setElementText(){},setText(){}},fe={dpr:t.ref(1),inputActive:x,mousePos:L},ye=t.computed((()=>$.value?.instance??null));const ve=t.computed((()=>K.value?.instance??null));const ge=t.computed((()=>_.value.instance));let be=null,xe=null;e.camera=ye,e.clearCustomRender=()=>{be?be.clearCustomRender():xe=null},e.createApp=e=>{be=t.createRenderer(he).createApp(e),Object.keys(m).forEach((e=>{be.component(e,m[e])}));const{mount:n}=be;return be.mount=(e,...t)=>{const r=N({domElement:"string"==typeof e?document.querySelector(e):e,isLunchboxRootNode:!0,name:"root",metaType:"rootMeta",type:"root",uuid:"LUNCHBOX_ROOT"});be.rootNode=r;return n(r,...t)},be.extend=e=>((({app:e,...t})=>{Object.keys(t).forEach((n=>{e.component(n,q(n)),l[n]=t[n]}))})({app:be,...e}),be),be.setCustomRender=e=>{be.customRender=e},xe&&(be.setCustomRender(xe),xe=null),be.clearCustomRender=()=>{be.customRender=null},be},e.find=function(e){return e=t.isRef(e)?e.value:e,y(e)?e?.instance:h(e)?e?.$el?.instance:t.isVNode(e)?e.el?.instance:null},e.globals=fe,e.offAfterRender=e=>{if(isFinite(e))ae.splice(e,1);else{const t=ae.findIndex((t=>t==e));ae.splice(t,1)}},e.offBeforeRender=e=>{if(isFinite(e))oe.splice(e,1);else{const t=oe.findIndex((t=>t==e));oe.splice(t,1)}},e.onAfterRender=(e,t=1/0)=>{t===1/0?ae.push(e):ae.splice(t,0,e)},e.onBeforeRender=ie,e.onStart=(e,t=1/0)=>{t===1/0?ne.push(e):ne.splice(t,0,e)},e.renderer=ve,e.scene=ge,e.setCustomRender=e=>{be?be.setCustomRender(e):xe=e},e.useCamera=function(e,n=!0){let r;r=t.watch(ye,(t=>{t&&(e(t),n&&r?.())}),{immediate:!0})},e.useRenderer=function(e,n=!0){let r;r=t.watch(ve,(t=>{t&&(e(t),n&&r?.())}),{immediate:!0})},e.useScene=function(e,n=!0){let r;r=t.watch(ge,(t=>{t&&(e(t),n&&r?.())}),{immediate:!0})},Object.defineProperty(e,"__esModule",{value:!0})}));
@@ -90,6 +90,7 @@ const LunchboxWrapper = {
90
90
  dpr: Number,
91
91
  ortho: Boolean,
92
92
  orthographic: Boolean,
93
+ rendererArguments: Object,
93
94
  rendererProperties: Object,
94
95
  shadow: [Boolean, Object],
95
96
  transparent: Boolean,
@@ -119,12 +120,11 @@ const LunchboxWrapper = {
119
120
  if (!renderer) {
120
121
  // build renderer args
121
122
  const rendererArgs = {
123
+ alpha: props.transparent,
122
124
  antialias: true,
123
125
  canvas: canvas.value.domElement,
126
+ ...(props.rendererArguments ?? {}),
124
127
  };
125
- if (props.transparent) {
126
- rendererArgs.alpha = true;
127
- }
128
128
  // create new renderer
129
129
  ensureRenderer.value = createNode({
130
130
  type: 'WebGLRenderer',
@@ -162,7 +162,6 @@ const LunchboxWrapper = {
162
162
  // the user has initialized the renderer, so anything depending
163
163
  // on the renderer can execute
164
164
  rendererReady.value = true;
165
- return;
166
165
  }
167
166
  // CAMERA
168
167
  // ====================
@@ -196,14 +195,17 @@ const LunchboxWrapper = {
196
195
  else {
197
196
  cameraReady.value = true;
198
197
  }
198
+ if (!camera.instance) {
199
+ throw new Error('Error creating camera.');
200
+ }
199
201
  // move camera if needed
200
202
  if (camera && props.cameraPosition) {
201
- camera.instance?.position.set(...props.cameraPosition);
203
+ camera.instance.position.set(...props.cameraPosition);
202
204
  }
203
205
  // angle camera if needed
204
206
  if (camera && (props.cameraLookAt || props.cameraLook)) {
205
207
  const source = (props.cameraLookAt || props.cameraLook);
206
- camera.instance?.lookAt(...source);
208
+ camera.instance.lookAt(...source);
207
209
  }
208
210
  // SCENE
209
211
  // ====================
@@ -226,11 +228,23 @@ const LunchboxWrapper = {
226
228
  else {
227
229
  throw new Error('missing renderer');
228
230
  }
231
+ // CALLBACK PREP
232
+ // ====================
233
+ const app = getCurrentInstance().appContext.app;
234
+ // START
235
+ // ====================
236
+ for (let startCallback of startCallbacks) {
237
+ startCallback({
238
+ app,
239
+ camera: camera.instance,
240
+ renderer: renderer.instance,
241
+ scene: scene.instance,
242
+ });
243
+ }
229
244
  // KICK UPDATE
230
245
  // ====================
231
- // console.log(scene)
232
246
  update({
233
- app: getCurrentInstance().appContext.app,
247
+ app,
234
248
  camera: camera.instance,
235
249
  renderer: renderer.instance,
236
250
  scene: scene.instance,
@@ -607,7 +621,6 @@ function addEventListener({ node, key, value, }) {
607
621
  // register click, pointerdown, pointerup
608
622
  if (key === 'onClick' || key === 'onPointerDown' || key === 'onPointerUp') {
609
623
  const stop = watch(() => inputActive.value, (isDown) => {
610
- console.log(isDown, currentIntersections);
611
624
  const idx = currentIntersections
612
625
  .map((v) => v.element)
613
626
  .findIndex((v) => v.instance &&
@@ -1240,6 +1253,16 @@ var MiniDom;
1240
1253
  const rootNode = new MiniDom.RendererRootNode();
1241
1254
  rootNode.minidomType = 'RootNode';
1242
1255
 
1256
+ const startCallbacks = [];
1257
+ const onStart = (cb, index = Infinity) => {
1258
+ if (index === Infinity) {
1259
+ startCallbacks.push(cb);
1260
+ }
1261
+ else {
1262
+ startCallbacks.splice(index, 0, cb);
1263
+ }
1264
+ };
1265
+
1243
1266
  let frameID;
1244
1267
  const beforeRender = [];
1245
1268
  const afterRender = [];
@@ -1662,9 +1685,51 @@ const globals = {
1662
1685
  inputActive,
1663
1686
  mousePos,
1664
1687
  };
1688
+ /** The current camera. Often easier to use `useCamera` instead of this. */
1665
1689
  const camera = computed(() => ensuredCamera.value?.instance ?? null);
1690
+ /** Run a function using the current camera when it's present. */
1691
+ function useCamera(callback, once = true) {
1692
+ let destroy;
1693
+ destroy = watch(camera, (newVal) => {
1694
+ if (!newVal)
1695
+ return;
1696
+ // TODO: better fix than `any`?
1697
+ callback(newVal);
1698
+ if (once) {
1699
+ destroy?.();
1700
+ }
1701
+ }, { immediate: true });
1702
+ }
1703
+ /** The current renderer. Often easier to use `useRenderer` instead of this. */
1666
1704
  const renderer = computed(() => ensureRenderer.value?.instance ?? null);
1705
+ /** Run a function using the current renderer when it's present. */
1706
+ function useRenderer(callback, once = true) {
1707
+ let destroy;
1708
+ destroy = watch(renderer, (newVal) => {
1709
+ if (!newVal)
1710
+ return;
1711
+ // TODO: better fix than `any`?
1712
+ callback(newVal);
1713
+ if (once) {
1714
+ destroy?.();
1715
+ }
1716
+ }, { immediate: true });
1717
+ }
1718
+ /** The current scene. Often easier to use `useScene` instead of this. */
1667
1719
  const scene = computed(() => ensuredScene.value.instance);
1720
+ /** Run a function using the current scene when it's present. */
1721
+ function useScene(callback, once = true) {
1722
+ let destroy;
1723
+ destroy = watch(scene, (newVal) => {
1724
+ if (!newVal)
1725
+ return;
1726
+ // TODO: better fix than `any`?
1727
+ callback(newVal);
1728
+ if (once) {
1729
+ destroy?.();
1730
+ }
1731
+ }, { immediate: true });
1732
+ }
1668
1733
  // CUSTOM RENDER SUPPORT
1669
1734
  // ====================
1670
1735
  let app = null;
@@ -1731,4 +1796,4 @@ const createApp = (root) => {
1731
1796
  return app;
1732
1797
  };
1733
1798
 
1734
- export { camera, clearCustomRender, createApp, find, globals, lunchboxRootNode as lunchboxTree, offAfterRender, offBeforeRender, onAfterRender, onBeforeRender, renderer, scene, setCustomRender };
1799
+ export { camera, clearCustomRender, createApp, find, globals, lunchboxRootNode as lunchboxTree, offAfterRender, offBeforeRender, onAfterRender, onBeforeRender, onStart, renderer, scene, setCustomRender, useCamera, useRenderer, useScene };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lunchboxjs",
3
- "version": "0.1.4006",
3
+ "version": "0.1.4010",
4
4
  "scripts": {
5
5
  "dev": "vite -c utils/vite.config.ts",
6
6
  "build": "vue-tsc --noEmit && vite build -c utils/vite.config.ts",
@@ -18,6 +18,7 @@ import {
18
18
  fallbackRendererUuid,
19
19
  MiniDom,
20
20
  rendererReady,
21
+ startCallbacks,
21
22
  tryGetNodeWithInstanceType,
22
23
  update,
23
24
  } from '../../core'
@@ -51,6 +52,7 @@ export const LunchboxWrapper: ComponentOptions = {
51
52
  dpr: Number,
52
53
  ortho: Boolean,
53
54
  orthographic: Boolean,
55
+ rendererArguments: Object,
54
56
  rendererProperties: Object,
55
57
  shadow: [Boolean, Object],
56
58
  transparent: Boolean,
@@ -82,11 +84,10 @@ export const LunchboxWrapper: ComponentOptions = {
82
84
  if (!renderer) {
83
85
  // build renderer args
84
86
  const rendererArgs: THREE.WebGLRendererParameters = {
87
+ alpha: props.transparent,
85
88
  antialias: true,
86
89
  canvas: canvas.value.domElement,
87
- }
88
- if (props.transparent) {
89
- rendererArgs.alpha = true
90
+ ...(props.rendererArguments ?? {}),
90
91
  }
91
92
 
92
93
  // create new renderer
@@ -137,7 +138,6 @@ export const LunchboxWrapper: ComponentOptions = {
137
138
  // the user has initialized the renderer, so anything depending
138
139
  // on the renderer can execute
139
140
  rendererReady.value = true
140
- return
141
141
  }
142
142
 
143
143
  // CAMERA
@@ -172,14 +172,17 @@ export const LunchboxWrapper: ComponentOptions = {
172
172
  } else {
173
173
  cameraReady.value = true
174
174
  }
175
+ if (!camera.instance) {
176
+ throw new Error('Error creating camera.')
177
+ }
175
178
  // move camera if needed
176
179
  if (camera && props.cameraPosition) {
177
- camera.instance?.position.set(...props.cameraPosition)
180
+ camera.instance.position.set(...props.cameraPosition)
178
181
  }
179
182
  // angle camera if needed
180
183
  if (camera && (props.cameraLookAt || props.cameraLook)) {
181
184
  const source = (props.cameraLookAt || props.cameraLook)!
182
- camera.instance?.lookAt(...source)
185
+ camera.instance.lookAt(...source)
183
186
  }
184
187
 
185
188
  // SCENE
@@ -209,11 +212,25 @@ export const LunchboxWrapper: ComponentOptions = {
209
212
  throw new Error('missing renderer')
210
213
  }
211
214
 
215
+ // CALLBACK PREP
216
+ // ====================
217
+ const app = getCurrentInstance()!.appContext.app as Lunch.App
218
+
219
+ // START
220
+ // ====================
221
+ for (let startCallback of startCallbacks) {
222
+ startCallback({
223
+ app,
224
+ camera: camera.instance,
225
+ renderer: renderer.instance,
226
+ scene: scene.instance,
227
+ })
228
+ }
229
+
212
230
  // KICK UPDATE
213
231
  // ====================
214
- // console.log(scene)
215
232
  update({
216
- app: getCurrentInstance()!.appContext.app as Lunch.App,
233
+ app,
217
234
  camera: camera.instance,
218
235
  renderer: renderer.instance,
219
236
  scene: scene.instance,
package/src/core/index.ts CHANGED
@@ -5,5 +5,6 @@ export * from './interaction'
5
5
  export * from './extend'
6
6
  export * from './instantiateThreeObject'
7
7
  export * from './minidom'
8
+ export * from './start'
8
9
  export * from './update'
9
- export * from './updateObjectProp'
10
+ export * from './updateObjectProp'
@@ -53,7 +53,6 @@ export function addEventListener({
53
53
  const stop = watch(
54
54
  () => inputActive.value,
55
55
  (isDown) => {
56
- console.log(isDown, currentIntersections)
57
56
  const idx = currentIntersections
58
57
  .map((v) => v.element)
59
58
  .findIndex(
@@ -0,0 +1,11 @@
1
+ import { Lunch } from '..'
2
+
3
+ export const startCallbacks = [] as Lunch.UpdateCallback[]
4
+
5
+ export const onStart = (cb: Lunch.UpdateCallback, index = Infinity) => {
6
+ if (index === Infinity) {
7
+ startCallbacks.push(cb)
8
+ } else {
9
+ startCallbacks.splice(index, 0, cb)
10
+ }
11
+ }
package/src/index.ts CHANGED
@@ -1,4 +1,11 @@
1
- import { computed, createRenderer, Component, ref, watch } from 'vue'
1
+ import {
2
+ computed,
3
+ createRenderer,
4
+ Component,
5
+ ref,
6
+ watch,
7
+ WatchStopHandle,
8
+ } from 'vue'
2
9
  import { nodeOps } from './nodeOps'
3
10
  import {
4
11
  // createdCamera,
@@ -20,8 +27,9 @@ export { lunchboxRootNode as lunchboxTree } from './core'
20
27
  export {
21
28
  offAfterRender,
22
29
  offBeforeRender,
23
- onBeforeRender,
24
30
  onAfterRender,
31
+ onBeforeRender,
32
+ onStart,
25
33
  } from './core'
26
34
  export * from './types'
27
35
 
@@ -35,9 +43,74 @@ export const globals = {
35
43
  mousePos,
36
44
  }
37
45
 
46
+ /** The current camera. Often easier to use `useCamera` instead of this. */
38
47
  export const camera = computed(() => ensuredCamera.value?.instance ?? null)
48
+ /** Run a function using the current camera when it's present. */
49
+ export function useCamera<T extends THREE.Camera = THREE.PerspectiveCamera>(
50
+ callback: (cam: T) => void,
51
+ once = true
52
+ ) {
53
+ let destroy: WatchStopHandle
54
+ destroy = watch(
55
+ camera,
56
+ (newVal) => {
57
+ if (!newVal) return
58
+
59
+ // TODO: better fix than `any`?
60
+ callback(newVal as any)
61
+ if (once) {
62
+ destroy?.()
63
+ }
64
+ },
65
+ { immediate: true }
66
+ )
67
+ }
68
+
69
+ /** The current renderer. Often easier to use `useRenderer` instead of this. */
39
70
  export const renderer = computed(() => ensureRenderer.value?.instance ?? null)
71
+ /** Run a function using the current renderer when it's present. */
72
+ export function useRenderer<T extends THREE.Renderer = THREE.WebGLRenderer>(
73
+ callback: (rend: T) => void,
74
+ once = true
75
+ ) {
76
+ let destroy: WatchStopHandle
77
+ destroy = watch(
78
+ renderer,
79
+ (newVal) => {
80
+ if (!newVal) return
81
+
82
+ // TODO: better fix than `any`?
83
+ callback(newVal as any)
84
+ if (once) {
85
+ destroy?.()
86
+ }
87
+ },
88
+ { immediate: true }
89
+ )
90
+ }
91
+
92
+ /** The current scene. Often easier to use `useScene` instead of this. */
40
93
  export const scene = computed(() => ensuredScene.value.instance)
94
+ /** Run a function using the current scene when it's present. */
95
+ export function useScene(
96
+ callback: (newScene: THREE.Scene) => void,
97
+ once = true
98
+ ) {
99
+ let destroy: WatchStopHandle
100
+ destroy = watch(
101
+ scene,
102
+ (newVal) => {
103
+ if (!newVal) return
104
+
105
+ // TODO: better fix than `any`?
106
+ callback(newVal as any)
107
+ if (once) {
108
+ destroy?.()
109
+ }
110
+ },
111
+ { immediate: true }
112
+ )
113
+ }
41
114
 
42
115
  // CUSTOM RENDER SUPPORT
43
116
  // ====================
package/src/types.ts CHANGED
@@ -145,6 +145,8 @@ export declare namespace Lunch {
145
145
  dpr?: number
146
146
  ortho?: boolean
147
147
  orthographic?: boolean
148
+ // TODO: Why doesn't ConstructorParameters<THREE.WebGLRenderer> work here?
149
+ rendererArguments?: object
148
150
  rendererProperties?: Partial<THREE.WebGLRenderer>
149
151
  shadow?: ShadowSugar
150
152
  transparent?: boolean