lunchboxjs 0.1.4002 → 0.1.4003

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.
@@ -1200,12 +1200,14 @@
1200
1200
  const beforeRender = [];
1201
1201
  const afterRender = [];
1202
1202
  const update = (opts) => {
1203
+ // request next frame
1203
1204
  frameID = requestAnimationFrame(() => update({
1204
1205
  app: opts.app,
1205
1206
  renderer: ensureRenderer.value?.instance,
1206
1207
  scene: ensuredScene.value.instance,
1207
1208
  camera: ensuredCamera.value.instance,
1208
1209
  }));
1210
+ // prep options
1209
1211
  const { app, renderer, scene, camera } = opts;
1210
1212
  // BEFORE RENDER
1211
1213
  beforeRender.forEach((cb) => {
@@ -1214,9 +1216,13 @@
1214
1216
  }
1215
1217
  });
1216
1218
  // RENDER
1217
- // console.log(camera?.position.z)
1218
1219
  if (renderer && scene && camera) {
1219
- renderer.render(vue.toRaw(scene), vue.toRaw(camera));
1220
+ if (app.customRender) {
1221
+ app.customRender(opts);
1222
+ }
1223
+ else {
1224
+ renderer.render(vue.toRaw(scene), vue.toRaw(camera));
1225
+ }
1220
1226
  }
1221
1227
  // AFTER RENDER
1222
1228
  afterRender.forEach((cb) => {
@@ -1597,8 +1603,30 @@
1597
1603
  const camera = vue.computed(() => ensuredCamera.value.instance);
1598
1604
  const renderer = vue.computed(() => ensureRenderer.value?.instance ?? null);
1599
1605
  const scene = vue.computed(() => ensuredScene.value.instance);
1606
+ // CUSTOM RENDER SUPPORT
1607
+ // ====================
1608
+ let app = null;
1609
+ let queuedCustomRenderFunction = null;
1610
+ /** Set a custom render function, overriding the Lunchbox app's default render function.
1611
+ * Changing this requires the user to manually render their scene.
1612
+ */
1613
+ const setCustomRender = (render) => {
1614
+ if (app)
1615
+ app.setCustomRender(render);
1616
+ else
1617
+ queuedCustomRenderFunction = render;
1618
+ };
1619
+ /** Clear the active app's custom render function. */
1620
+ const clearCustomRender = () => {
1621
+ if (app)
1622
+ app.clearCustomRender();
1623
+ else
1624
+ queuedCustomRenderFunction = null;
1625
+ };
1626
+ // CREATE APP
1627
+ // ====================
1600
1628
  const createApp = (root) => {
1601
- const app = vue.createRenderer(nodeOps).createApp(root);
1629
+ app = vue.createRenderer(nodeOps).createApp(root);
1602
1630
  // register all components
1603
1631
  Object.keys(components).forEach((key) => {
1604
1632
  app.component(key, components[key]);
@@ -1621,14 +1649,28 @@
1621
1649
  };
1622
1650
  // embed .extend function
1623
1651
  app.extend = (targets) => {
1624
- extend({ app, ...targets });
1652
+ extend({ app: app, ...targets });
1625
1653
  return app;
1626
1654
  };
1655
+ // prep for custom render support
1656
+ app.setCustomRender = (newRender) => {
1657
+ app.customRender = newRender;
1658
+ };
1659
+ // add queued custom render if we have one
1660
+ if (queuedCustomRenderFunction) {
1661
+ app.setCustomRender(queuedCustomRenderFunction);
1662
+ queuedCustomRenderFunction = null;
1663
+ }
1664
+ // add custom render removal
1665
+ app.clearCustomRender = () => {
1666
+ app.customRender = null;
1667
+ };
1627
1668
  // done
1628
1669
  return app;
1629
1670
  };
1630
1671
 
1631
1672
  exports.camera = camera;
1673
+ exports.clearCustomRender = clearCustomRender;
1632
1674
  exports.createApp = createApp;
1633
1675
  exports.find = find;
1634
1676
  exports.globals = globals;
@@ -1636,7 +1678,7 @@
1636
1678
  exports.onBeforeRender = onBeforeRender;
1637
1679
  exports.renderer = renderer;
1638
1680
  exports.scene = scene;
1639
- exports.update = update;
1681
+ exports.setCustomRender = setCustomRender;
1640
1682
 
1641
1683
  Object.defineProperty(exports, '__esModule', { value: true });
1642
1684
 
@@ -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=$.value?.instance,o=U.value.instance;if(!r?.domElement||!o)return;const a=(e=e??window.innerWidth)/(n=n??window.innerHeight),s=k.value;if("perspectivecamera"===s.type?.toLowerCase()){const e=s.instance;e.aspect=a,e.updateProjectionMatrix()}else console.log("TODO: ortho camera update");r.setSize(e,n),o&&s.instance&&r.render(t.toRaw(o),t.toRaw(s.instance))},c=e=>({position:e,top:0,right:0,bottom:0,left:0,width:"100%",height:"100%"}),d={name:"Lunchbox",props:{background:String,cameraPosition:Array,dpr:Number,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;return t.onMounted((()=>{if(!a.value)throw new Error("missing canvas");const o=k.value.instance;if(o&&e.cameraPosition&&o.position.set(...e.cameraPosition),l=B(["WebGLRenderer"]),l)return s.value=!1,void(F.value=!0);{const t={antialias:!0,canvas:a.value.domElement};e.transparent&&(t.alpha=!0),$.value=v({type:"WebGLRenderer",uuid:S,props:{args:[t]}}),F.value=!0;const n=$,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=U.value,p&&p.instance&&e.background&&(p.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),ue.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),te({app:t.getCurrentInstance().appContext.app,camera:o,renderer:l.instance,scene:p.instance})})),t.onBeforeUnmount((()=>{re()})),()=>[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={},l=["canvas","div","LunchboxWrapper"],p={...["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"].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))),Lunchbox:d};const h=e=>e?.$el&&e?.$el?.hasOwnProperty?.("instance"),m=e=>{if("domMeta"===e?.metaType)return!0;const t="string"==typeof e?e:e?.type;return l.includes(t??"")},f=e=>"standardMeta"===e?.metaType,y=e=>e.isLunchboxRootNode;function v(e={},t={}){const n={attached:e.attached??[],attachedArray:e.attachedArray??{},instance:e.instance??null},r=new H.RendererStandardNode({...e,...n,metaType:"standardMeta"});return!r.type||y(r)||r.instance||(r.instance=function(e){if(!e.type)return null;const t=e.type[0].toUpperCase()+e.type.slice(1),n=u[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&&(U.value=r),r}const b=[],x=t.ref(!1);function g({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)&&(W.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=P.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:P[r].intersection})})))}));e.eventListenerRemoveFunctions[n].push(r)}return e}const w=["onClick","onPointerUp","onPointerDown","onPointerOver","onPointerOut","onPointerEnter","onPointerLeave","onPointerMove"];let E,R,A;const L=t.ref({x:1/0,y:1/0});let C=!1;let P=[];const M=()=>{const e=W.value?.instance,t=k.value?.instance;if(!e||!t)return;e.setFromCamera(ue.mousePos.value,t);const n=e.intersectObjects(b.map((e=>e.instance)));let r=[],o=[],a=[];r=P.map((e=>e.intersection)),n?.forEach((e=>{const t=P.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})})),P=[].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 H.RendererRootNode(t)),e.lunchboxTree}function B(e){Array.isArray(e)||(e=[e]);for(let t of e)if(O[t])return O[t];for(let t of e){const e=T[t]||s.find((e=>e.type?.toLowerCase()===t.toLowerCase()));if(e){const n=e;return T[t]=n,n}}return null}e.lunchboxTree=void 0;const T=t.reactive({}),O=t.reactive({});function j(e,n,r={},o=null){Array.isArray(e)||(e=[e]);for(let t of e)T[t]||(T[t]=null),O[t]||(O[t]=null);return t.computed({get(){const t=B(e);if(t)return t;const a=N(),s=v({type:e[0],uuid:n,props:r});return a.addChild(s),T[e[0]]=s,o&&o(s),s},set(e){const t=e.type??"",n=t[0].toUpperCase()+t.slice(1);O[n]=e}})}const k=j(["PerspectiveCamera","OrthographicCamera"],"FALLBACK_CAMERA",{args:[45,.5625,1,1e3]}),S="FALLBACK_RENDERER",D=j(["WebGLRenderer"],S,{}),F=t.ref(!1),$=t.computed({get:()=>F.value?D.value:null,set(e){const t=e.type??"",n=t[0].toUpperCase()+t.slice(1);O[n]=e}}),U=j("Scene","FALLBACK_SCENE"),W=j("Raycaster","AUTO_RAYCASTER",{},(e=>(e=>{if(!e.instance)return;let n=null;n=t.watch((()=>$.value),(e=>{e?.instance&&(C||(E=t=>{const n=(e.instance.domElement.width??1)/ue.dpr.value,r=(e.instance.domElement.height??1)/ue.dpr.value;L.value.x=t.offsetX/n*2-1,L.value.y=-t.offsetY/r*2+1},R=()=>x.value=!0,A=()=>x.value=!1,e.instance.domElement.addEventListener("mousemove",E),e.instance.domElement.addEventListener("mousedown",R),e.instance.domElement.addEventListener("mouseup",A),ne(M),C=!0),n&&n())}),{immediate:!0})})(e))),I=e=>t.defineComponent({inheritAttrs:!1,name:e,render(){return t.h(e,this.$attrs,this.$slots?.default?.()||[])}});var K,_=new Uint8Array(16);function V(){if(!K&&!(K="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 K(_)}var q=/^(?:[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 z(e){return"string"==typeof e&&q.test(e)}for(var H,Y=[],X=0;X<256;++X)Y.push((X+256).toString(16).substr(1));function J(e,t,n){var r=(e=e||{}).random||(e.rng||V)();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=(Y[e[t+0]]+Y[e[t+1]]+Y[e[t+2]]+Y[e[t+3]]+"-"+Y[e[t+4]]+Y[e[t+5]]+"-"+Y[e[t+6]]+Y[e[t+7]]+"-"+Y[e[t+8]]+Y[e[t+9]]+"-"+Y[e[t+10]]+Y[e[t+11]]+Y[e[t+12]]+Y[e[t+13]]+Y[e[t+14]]+Y[e[t+15]]).toLowerCase();if(!z(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??J(),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}(H||(H={}));let Q;(new H.RendererRootNode).minidomType="RootNode";const Z=[],ee=[],te=e=>{Q=requestAnimationFrame((()=>te({app:e.app,renderer:$.value?.instance,scene:U.value.instance,camera:k.value.instance})));const{app:n,renderer:r,scene:o,camera:a}=e;Z.forEach((t=>{t&&t(e)})),r&&o&&a&&r.render(t.toRaw(o),t.toRaw(a)),ee.forEach((t=>{t&&t(e)}))},ne=(e,t=1/0)=>{t===1/0?Z.push(e):Z.splice(t,0,e)},re=()=>{Q&&cancelAnimationFrame(Q)};const oe={x:"position.x",y:"position.y",z:"position.z"},ae=["","parameters"],se=["args","attach","attachArray","key","onAdded","ref","src"],ie=["geometry","material"];function ce(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 de={createElement:(e,t,n,r)=>{const o={type:e};r&&(o.props=r);if(m(e)){const e=function(e={}){const t={domElement:document.createElement(e.type??"")};return new H.RendererDomNode({...t,...e,metaType:"domMeta"})}(o);return e}const a=v(o);return ie.forEach((t=>{e.toLowerCase().endsWith(t)&&(a.props.attach=t)})),a},createText:e=>function(e={}){const t={text:e.text??""};return new H.RendererTextNode({...e,...t,metaType:"textMeta"})}({text:e}),createComment:e=>function(e={}){const t={text:e.text??""};return new H.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&&(m(e)&&(m(t)||y(t))&&t.domElement.appendChild(e.domElement),f(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&&y(r)){const t=U.value;t.instance&&e&&t.addChild(e),e.instance&&e.instance.isObject3D&&t.instance&&t!==e&&t.instance.add(e.instance)}else f(e)&&e.instance?.isObject3D&&f(r)&&r.instance?.isObject3D&&r.instance?.add?.(e.instance);if(e?.props?.attach&&f(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);ce(e,t,e.props.attach,r)}else n.load(e.props.src,(n=>{ce(e,t,e.props.attach,n)}),null,(e=>{throw new Error(e)}))}(e,t):ce(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){m(e)?"style"===t?Object.keys(o).forEach((t=>{e.domElement.style[t]=o[t]})):e.domElement.setAttribute(t,o):y(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 g({node:e,key:t,value:n});if(se.includes(t))return e;if(!f(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=oe[a]||a;for(let e=0;e<ae.length&&!s;e++){const t=[ae[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(O),n=[];e.walk((e=>(n.push(e),!0))),n.forEach((e=>{const n=t.find((t=>O[t]?.uuid===e.uuid));if(n&&(O[n]=null),f(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(){}},ue={dpr:t.ref(1),inputActive:x,mousePos:L},le=t.computed((()=>k.value.instance)),pe=t.computed((()=>$.value?.instance??null)),he=t.computed((()=>U.value.instance));e.camera=le,e.createApp=e=>{const n=t.createRenderer(de).createApp(e);Object.keys(p).forEach((e=>{n.component(e,p[e])}));const{mount:r}=n;return n.mount=(e,...t)=>{const o=N({domElement:"string"==typeof e?document.querySelector(e):e,isLunchboxRootNode:!0,name:"root",metaType:"rootMeta",type:"root",uuid:"LUNCHBOX_ROOT"});n.rootNode=o;return r(o,...t)},n.extend=e=>((({app:e,...t})=>{Object.keys(t).forEach((n=>{e.component(n,I(n)),u[n]=t[n]}))})({app:n,...e}),n),n},e.find=function(e){return e=t.isRef(e)?e.value:e,f(e)?e?.instance:h(e)?e?.$el?.instance:t.isVNode(e)?e.el?.instance:null},e.globals=ue,e.onAfterRender=(e,t=1/0)=>{t===1/0?ee.push(e):ee.splice(t,0,e)},e.onBeforeRender=ne,e.renderer=pe,e.scene=he,e.update=te,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=$.value?.instance,o=U.value.instance;if(!r?.domElement||!o)return;const a=(e=e??window.innerWidth)/(n=n??window.innerHeight),s=k.value;if("perspectivecamera"===s.type?.toLowerCase()){const e=s.instance;e.aspect=a,e.updateProjectionMatrix()}else console.log("TODO: ortho camera update");r.setSize(e,n),o&&s.instance&&r.render(t.toRaw(o),t.toRaw(s.instance))},c=e=>({position:e,top:0,right:0,bottom:0,left:0,width:"100%",height:"100%"}),d={name:"Lunchbox",props:{background:String,cameraPosition:Array,dpr:Number,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;return t.onMounted((()=>{if(!a.value)throw new Error("missing canvas");const o=k.value.instance;if(o&&e.cameraPosition&&o.position.set(...e.cameraPosition),l=B(["WebGLRenderer"]),l)return s.value=!1,void(F.value=!0);{const t={antialias:!0,canvas:a.value.domElement};e.transparent&&(t.alpha=!0),$.value=v({type:"WebGLRenderer",uuid:S,props:{args:[t]}}),F.value=!0;const n=$,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=U.value,p&&p.instance&&e.background&&(p.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),ue.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),te({app:t.getCurrentInstance().appContext.app,camera:o,renderer:l.instance,scene:p.instance})})),t.onBeforeUnmount((()=>{re()})),()=>[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={},l=["canvas","div","LunchboxWrapper"],p={...["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"].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))),Lunchbox:d};const m=e=>e?.$el&&e?.$el?.hasOwnProperty?.("instance"),h=e=>{if("domMeta"===e?.metaType)return!0;const t="string"==typeof e?e:e?.type;return l.includes(t??"")},f=e=>"standardMeta"===e?.metaType,y=e=>e.isLunchboxRootNode;function v(e={},t={}){const n={attached:e.attached??[],attachedArray:e.attachedArray??{},instance:e.instance??null},r=new H.RendererStandardNode({...e,...n,metaType:"standardMeta"});return!r.type||y(r)||r.instance||(r.instance=function(e){if(!e.type)return null;const t=e.type[0].toUpperCase()+e.type.slice(1),n=u[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&&(U.value=r),r}const b=[],x=t.ref(!1);function g({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),R.includes(n)&&(W.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=P.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:P[r].intersection})})))}));e.eventListenerRemoveFunctions[n].push(r)}return e}const R=["onClick","onPointerUp","onPointerDown","onPointerOver","onPointerOut","onPointerEnter","onPointerLeave","onPointerMove"];let w,E,A;const C=t.ref({x:1/0,y:1/0});let L=!1;let P=[];const M=()=>{const e=W.value?.instance,t=k.value?.instance;if(!e||!t)return;e.setFromCamera(ue.mousePos.value,t);const n=e.intersectObjects(b.map((e=>e.instance)));let r=[],o=[],a=[];r=P.map((e=>e.intersection)),n?.forEach((e=>{const t=P.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})})),P=[].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 H.RendererRootNode(t)),e.lunchboxTree}function B(e){Array.isArray(e)||(e=[e]);for(let t of e)if(O[t])return O[t];for(let t of e){const e=T[t]||s.find((e=>e.type?.toLowerCase()===t.toLowerCase()));if(e){const n=e;return T[t]=n,n}}return null}e.lunchboxTree=void 0;const T=t.reactive({}),O=t.reactive({});function j(e,n,r={},o=null){Array.isArray(e)||(e=[e]);for(let t of e)T[t]||(T[t]=null),O[t]||(O[t]=null);return t.computed({get(){const t=B(e);if(t)return t;const a=N(),s=v({type:e[0],uuid:n,props:r});return a.addChild(s),T[e[0]]=s,o&&o(s),s},set(e){const t=e.type??"",n=t[0].toUpperCase()+t.slice(1);O[n]=e}})}const k=j(["PerspectiveCamera","OrthographicCamera"],"FALLBACK_CAMERA",{args:[45,.5625,1,1e3]}),S="FALLBACK_RENDERER",D=j(["WebGLRenderer"],S,{}),F=t.ref(!1),$=t.computed({get:()=>F.value?D.value:null,set(e){const t=e.type??"",n=t[0].toUpperCase()+t.slice(1);O[n]=e}}),U=j("Scene","FALLBACK_SCENE"),W=j("Raycaster","AUTO_RAYCASTER",{},(e=>(e=>{if(!e.instance)return;let n=null;n=t.watch((()=>$.value),(e=>{e?.instance&&(L||(w=t=>{const n=(e.instance.domElement.width??1)/ue.dpr.value,r=(e.instance.domElement.height??1)/ue.dpr.value;C.value.x=t.offsetX/n*2-1,C.value.y=-t.offsetY/r*2+1},E=()=>x.value=!0,A=()=>x.value=!1,e.instance.domElement.addEventListener("mousemove",w),e.instance.domElement.addEventListener("mousedown",E),e.instance.domElement.addEventListener("mouseup",A),ne(M),L=!0),n&&n())}),{immediate:!0})})(e))),I=e=>t.defineComponent({inheritAttrs:!1,name:e,render(){return t.h(e,this.$attrs,this.$slots?.default?.()||[])}});var K,_=new Uint8Array(16);function V(){if(!K&&!(K="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 K(_)}var q=/^(?:[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 z(e){return"string"==typeof e&&q.test(e)}for(var H,Y=[],X=0;X<256;++X)Y.push((X+256).toString(16).substr(1));function J(e,t,n){var r=(e=e||{}).random||(e.rng||V)();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=(Y[e[t+0]]+Y[e[t+1]]+Y[e[t+2]]+Y[e[t+3]]+"-"+Y[e[t+4]]+Y[e[t+5]]+"-"+Y[e[t+6]]+Y[e[t+7]]+"-"+Y[e[t+8]]+Y[e[t+9]]+"-"+Y[e[t+10]]+Y[e[t+11]]+Y[e[t+12]]+Y[e[t+13]]+Y[e[t+14]]+Y[e[t+15]]).toLowerCase();if(!z(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??J(),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}(H||(H={}));let Q;(new H.RendererRootNode).minidomType="RootNode";const Z=[],ee=[],te=e=>{Q=requestAnimationFrame((()=>te({app:e.app,renderer:$.value?.instance,scene:U.value.instance,camera:k.value.instance})));const{app:n,renderer:r,scene:o,camera:a}=e;Z.forEach((t=>{t&&t(e)})),r&&o&&a&&(n.customRender?n.customRender(e):r.render(t.toRaw(o),t.toRaw(a))),ee.forEach((t=>{t&&t(e)}))},ne=(e,t=1/0)=>{t===1/0?Z.push(e):Z.splice(t,0,e)},re=()=>{Q&&cancelAnimationFrame(Q)};const oe={x:"position.x",y:"position.y",z:"position.z"},ae=["","parameters"],se=["args","attach","attachArray","key","onAdded","ref","src"],ie=["geometry","material"];function ce(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 de={createElement:(e,t,n,r)=>{const o={type:e};r&&(o.props=r);if(h(e)){const e=function(e={}){const t={domElement:document.createElement(e.type??"")};return new H.RendererDomNode({...t,...e,metaType:"domMeta"})}(o);return e}const a=v(o);return ie.forEach((t=>{e.toLowerCase().endsWith(t)&&(a.props.attach=t)})),a},createText:e=>function(e={}){const t={text:e.text??""};return new H.RendererTextNode({...e,...t,metaType:"textMeta"})}({text:e}),createComment:e=>function(e={}){const t={text:e.text??""};return new H.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&&(h(e)&&(h(t)||y(t))&&t.domElement.appendChild(e.domElement),f(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&&y(r)){const t=U.value;t.instance&&e&&t.addChild(e),e.instance&&e.instance.isObject3D&&t.instance&&t!==e&&t.instance.add(e.instance)}else f(e)&&e.instance?.isObject3D&&f(r)&&r.instance?.isObject3D&&r.instance?.add?.(e.instance);if(e?.props?.attach&&f(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);ce(e,t,e.props.attach,r)}else n.load(e.props.src,(n=>{ce(e,t,e.props.attach,n)}),null,(e=>{throw new Error(e)}))}(e,t):ce(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){h(e)?"style"===t?Object.keys(o).forEach((t=>{e.domElement.style[t]=o[t]})):e.domElement.setAttribute(t,o):y(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 g({node:e,key:t,value:n});if(se.includes(t))return e;if(!f(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=oe[a]||a;for(let e=0;e<ae.length&&!s;e++){const t=[ae[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(O),n=[];e.walk((e=>(n.push(e),!0))),n.forEach((e=>{const n=t.find((t=>O[t]?.uuid===e.uuid));if(n&&(O[n]=null),f(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(){}},ue={dpr:t.ref(1),inputActive:x,mousePos:C},le=t.computed((()=>k.value.instance)),pe=t.computed((()=>$.value?.instance??null)),me=t.computed((()=>U.value.instance));let he=null,fe=null;e.camera=le,e.clearCustomRender=()=>{he?he.clearCustomRender():fe=null},e.createApp=e=>{he=t.createRenderer(de).createApp(e),Object.keys(p).forEach((e=>{he.component(e,p[e])}));const{mount:n}=he;return he.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"});he.rootNode=r;return n(r,...t)},he.extend=e=>((({app:e,...t})=>{Object.keys(t).forEach((n=>{e.component(n,I(n)),u[n]=t[n]}))})({app:he,...e}),he),he.setCustomRender=e=>{he.customRender=e},fe&&(he.setCustomRender(fe),fe=null),he.clearCustomRender=()=>{he.customRender=null},he},e.find=function(e){return e=t.isRef(e)?e.value:e,f(e)?e?.instance:m(e)?e?.$el?.instance:t.isVNode(e)?e.el?.instance:null},e.globals=ue,e.onAfterRender=(e,t=1/0)=>{t===1/0?ee.push(e):ee.splice(t,0,e)},e.onBeforeRender=ne,e.renderer=pe,e.scene=me,e.setCustomRender=e=>{he?he.setCustomRender(e):fe=e},Object.defineProperty(e,"__esModule",{value:!0})}));
@@ -1179,12 +1179,14 @@ let frameID;
1179
1179
  const beforeRender = [];
1180
1180
  const afterRender = [];
1181
1181
  const update = (opts) => {
1182
+ // request next frame
1182
1183
  frameID = requestAnimationFrame(() => update({
1183
1184
  app: opts.app,
1184
1185
  renderer: ensureRenderer.value?.instance,
1185
1186
  scene: ensuredScene.value.instance,
1186
1187
  camera: ensuredCamera.value.instance,
1187
1188
  }));
1189
+ // prep options
1188
1190
  const { app, renderer, scene, camera } = opts;
1189
1191
  // BEFORE RENDER
1190
1192
  beforeRender.forEach((cb) => {
@@ -1193,9 +1195,13 @@ const update = (opts) => {
1193
1195
  }
1194
1196
  });
1195
1197
  // RENDER
1196
- // console.log(camera?.position.z)
1197
1198
  if (renderer && scene && camera) {
1198
- renderer.render(toRaw(scene), toRaw(camera));
1199
+ if (app.customRender) {
1200
+ app.customRender(opts);
1201
+ }
1202
+ else {
1203
+ renderer.render(toRaw(scene), toRaw(camera));
1204
+ }
1199
1205
  }
1200
1206
  // AFTER RENDER
1201
1207
  afterRender.forEach((cb) => {
@@ -1576,8 +1582,30 @@ const globals = {
1576
1582
  const camera = computed(() => ensuredCamera.value.instance);
1577
1583
  const renderer = computed(() => ensureRenderer.value?.instance ?? null);
1578
1584
  const scene = computed(() => ensuredScene.value.instance);
1585
+ // CUSTOM RENDER SUPPORT
1586
+ // ====================
1587
+ let app = null;
1588
+ let queuedCustomRenderFunction = null;
1589
+ /** Set a custom render function, overriding the Lunchbox app's default render function.
1590
+ * Changing this requires the user to manually render their scene.
1591
+ */
1592
+ const setCustomRender = (render) => {
1593
+ if (app)
1594
+ app.setCustomRender(render);
1595
+ else
1596
+ queuedCustomRenderFunction = render;
1597
+ };
1598
+ /** Clear the active app's custom render function. */
1599
+ const clearCustomRender = () => {
1600
+ if (app)
1601
+ app.clearCustomRender();
1602
+ else
1603
+ queuedCustomRenderFunction = null;
1604
+ };
1605
+ // CREATE APP
1606
+ // ====================
1579
1607
  const createApp = (root) => {
1580
- const app = createRenderer(nodeOps).createApp(root);
1608
+ app = createRenderer(nodeOps).createApp(root);
1581
1609
  // register all components
1582
1610
  Object.keys(components).forEach((key) => {
1583
1611
  app.component(key, components[key]);
@@ -1600,11 +1628,24 @@ const createApp = (root) => {
1600
1628
  };
1601
1629
  // embed .extend function
1602
1630
  app.extend = (targets) => {
1603
- extend({ app, ...targets });
1631
+ extend({ app: app, ...targets });
1604
1632
  return app;
1605
1633
  };
1634
+ // prep for custom render support
1635
+ app.setCustomRender = (newRender) => {
1636
+ app.customRender = newRender;
1637
+ };
1638
+ // add queued custom render if we have one
1639
+ if (queuedCustomRenderFunction) {
1640
+ app.setCustomRender(queuedCustomRenderFunction);
1641
+ queuedCustomRenderFunction = null;
1642
+ }
1643
+ // add custom render removal
1644
+ app.clearCustomRender = () => {
1645
+ app.customRender = null;
1646
+ };
1606
1647
  // done
1607
1648
  return app;
1608
1649
  };
1609
1650
 
1610
- export { camera, createApp, find, globals, lunchboxRootNode as lunchboxTree, onAfterRender, onBeforeRender, renderer, scene, update };
1651
+ export { camera, clearCustomRender, createApp, find, globals, lunchboxRootNode as lunchboxTree, onAfterRender, onBeforeRender, renderer, scene, setCustomRender };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lunchboxjs",
3
- "version": "0.1.4002",
3
+ "version": "0.1.4003",
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",
@@ -7,12 +7,8 @@ let frameID: number
7
7
  export const beforeRender = [] as Lunch.UpdateCallback[]
8
8
  export const afterRender = [] as Lunch.UpdateCallback[]
9
9
 
10
- export const update: Lunch.UpdateCallback = (opts: {
11
- app: Lunch.App
12
- renderer?: THREE.Renderer | null
13
- scene?: THREE.Scene | null
14
- camera?: THREE.Camera | null
15
- }) => {
10
+ export const update: Lunch.UpdateCallback = (opts) => {
11
+ // request next frame
16
12
  frameID = requestAnimationFrame(() =>
17
13
  update({
18
14
  app: opts.app,
@@ -22,6 +18,7 @@ export const update: Lunch.UpdateCallback = (opts: {
22
18
  })
23
19
  )
24
20
 
21
+ // prep options
25
22
  const { app, renderer, scene, camera } = opts
26
23
 
27
24
  // BEFORE RENDER
@@ -32,9 +29,12 @@ export const update: Lunch.UpdateCallback = (opts: {
32
29
  })
33
30
 
34
31
  // RENDER
35
- // console.log(camera?.position.z)
36
32
  if (renderer && scene && camera) {
37
- renderer.render(toRaw(scene), toRaw(camera))
33
+ if (app.customRender) {
34
+ app.customRender(opts)
35
+ } else {
36
+ renderer.render(toRaw(scene), toRaw(camera))
37
+ }
38
38
  }
39
39
 
40
40
  // AFTER RENDER
package/src/index.ts CHANGED
@@ -12,13 +12,12 @@ import {
12
12
  inputActive,
13
13
  mousePos,
14
14
  rootUuid,
15
- update,
16
15
  } from './core'
17
16
  import { components } from './components'
18
17
  import { Lunch } from './types'
19
18
 
20
19
  export { lunchboxRootNode as lunchboxTree } from './core'
21
- export { onBeforeRender, onAfterRender, update } from './core'
20
+ export { onBeforeRender, onAfterRender } from './core'
22
21
  export * from './types'
23
22
 
24
23
  // Utilities
@@ -35,12 +34,37 @@ export const camera = computed(() => ensuredCamera.value.instance)
35
34
  export const renderer = computed(() => ensureRenderer.value?.instance ?? null)
36
35
  export const scene = computed(() => ensuredScene.value.instance)
37
36
 
37
+ // CUSTOM RENDER SUPPORT
38
+ // ====================
39
+ let app: Lunch.App | null = null
40
+ let queuedCustomRenderFunction:
41
+ | ((opts: Lunch.UpdateCallbackProperties) => void)
42
+ | null = null
43
+
44
+ /** Set a custom render function, overriding the Lunchbox app's default render function.
45
+ * Changing this requires the user to manually render their scene.
46
+ */
47
+ export const setCustomRender = (
48
+ render: (opts: Lunch.UpdateCallbackProperties) => void
49
+ ) => {
50
+ if (app) app.setCustomRender(render)
51
+ else queuedCustomRenderFunction = render
52
+ }
53
+
54
+ /** Clear the active app's custom render function. */
55
+ export const clearCustomRender = () => {
56
+ if (app) app.clearCustomRender()
57
+ else queuedCustomRenderFunction = null
58
+ }
59
+
60
+ // CREATE APP
61
+ // ====================
38
62
  export const createApp = (root: Component) => {
39
- const app = createRenderer(nodeOps).createApp(root) as Lunch.App
63
+ app = createRenderer(nodeOps).createApp(root) as Lunch.App
40
64
 
41
65
  // register all components
42
66
  Object.keys(components).forEach((key) => {
43
- app.component(key, (components as any)[key])
67
+ app!.component(key, (components as any)[key])
44
68
  })
45
69
 
46
70
  // update mount function to match Lunchbox.Node
@@ -57,15 +81,33 @@ export const createApp = (root: Component) => {
57
81
  type: 'root',
58
82
  uuid: rootUuid,
59
83
  })
60
- app.rootNode = rootNode
84
+ app!.rootNode = rootNode
61
85
  const mounted = mount(rootNode, ...args)
62
86
  return mounted
63
87
  }
64
88
 
65
89
  // embed .extend function
66
90
  app.extend = (targets: Record<string, any>) => {
67
- extend({ app, ...targets })
68
- return app
91
+ extend({ app: app!, ...targets })
92
+ return app!
93
+ }
94
+
95
+ // prep for custom render support
96
+ app.setCustomRender = (
97
+ newRender: (opts: Lunch.UpdateCallbackProperties) => void
98
+ ) => {
99
+ app!.customRender = newRender
100
+ }
101
+
102
+ // add queued custom render if we have one
103
+ if (queuedCustomRenderFunction) {
104
+ app.setCustomRender(queuedCustomRenderFunction)
105
+ queuedCustomRenderFunction = null
106
+ }
107
+
108
+ // add custom render removal
109
+ app.clearCustomRender = () => {
110
+ app!.customRender = null
69
111
  }
70
112
 
71
113
  // done
package/src/types.ts CHANGED
@@ -7,8 +7,13 @@ type RendererStandardNode<T = THREE.Object3D> =
7
7
  export declare namespace Lunch {
8
8
  /** Lunchbox app. */
9
9
  type App = VueApp<any> & {
10
+ clearCustomRender: () => void
11
+ customRender: ((opts: UpdateCallbackProperties) => void) | null
10
12
  extend: (v: Record<string, any>) => App
11
13
  rootNode: RootNode
14
+ setCustomRender: (
15
+ update: (opts: UpdateCallbackProperties) => void
16
+ ) => void
12
17
  update: UpdateCallback
13
18
  }
14
19