lunchboxjs 0.1.4006-dev002 → 0.1.4012

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.
package/dist/.DS_Store ADDED
Binary file
@@ -111,9 +111,11 @@
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,
118
+ zoom: Number,
117
119
  },
118
120
  setup(props, context) {
119
121
  const canvas = vue.ref();
@@ -140,12 +142,11 @@
140
142
  if (!renderer) {
141
143
  // build renderer args
142
144
  const rendererArgs = {
145
+ alpha: props.transparent,
143
146
  antialias: true,
144
147
  canvas: canvas.value.domElement,
148
+ ...(props.rendererArguments ?? {}),
145
149
  };
146
- if (props.transparent) {
147
- rendererArgs.alpha = true;
148
- }
149
150
  // create new renderer
150
151
  ensureRenderer.value = createNode({
151
152
  type: 'WebGLRenderer',
@@ -183,7 +184,6 @@
183
184
  // the user has initialized the renderer, so anything depending
184
185
  // on the renderer can execute
185
186
  rendererReady.value = true;
186
- return;
187
187
  }
188
188
  // CAMERA
189
189
  // ====================
@@ -217,14 +217,21 @@
217
217
  else {
218
218
  cameraReady.value = true;
219
219
  }
220
+ if (!camera.instance) {
221
+ throw new Error('Error creating camera.');
222
+ }
220
223
  // move camera if needed
221
224
  if (camera && props.cameraPosition) {
222
- camera.instance?.position.set(...props.cameraPosition);
225
+ camera.instance.position.set(...props.cameraPosition);
223
226
  }
224
227
  // angle camera if needed
225
228
  if (camera && (props.cameraLookAt || props.cameraLook)) {
226
229
  const source = (props.cameraLookAt || props.cameraLook);
227
- camera.instance?.lookAt(...source);
230
+ camera.instance.lookAt(...source);
231
+ }
232
+ // zoom camera if needed
233
+ if (camera && props.zoom !== undefined) {
234
+ camera.instance.zoom = props.zoom;
228
235
  }
229
236
  // SCENE
230
237
  // ====================
@@ -247,11 +254,23 @@
247
254
  else {
248
255
  throw new Error('missing renderer');
249
256
  }
257
+ // CALLBACK PREP
258
+ // ====================
259
+ const app = vue.getCurrentInstance().appContext.app;
260
+ // START
261
+ // ====================
262
+ for (let startCallback of startCallbacks) {
263
+ startCallback({
264
+ app,
265
+ camera: camera.instance,
266
+ renderer: renderer.instance,
267
+ scene: scene.instance,
268
+ });
269
+ }
250
270
  // KICK UPDATE
251
271
  // ====================
252
- // console.log(scene)
253
272
  update({
254
- app: vue.getCurrentInstance().appContext.app,
273
+ app,
255
274
  camera: camera.instance,
256
275
  renderer: renderer.instance,
257
276
  scene: scene.instance,
@@ -456,15 +475,20 @@
456
475
  inheritAttrs: false,
457
476
  name: tag,
458
477
  setup(props, context) {
459
- return () => vue.h(tag, context.attrs, context.slots?.default?.() || []);
478
+ return () => {
479
+ return vue.h(tag, context.attrs, context.slots?.default?.() || []);
480
+ };
460
481
  },
461
482
  });
462
- autoGeneratedComponents.map(createComponent$1).reduce((acc, curr) => {
483
+ // turn components into registered map
484
+ const processed = autoGeneratedComponents
485
+ .map(createComponent$1)
486
+ .reduce((acc, curr) => {
463
487
  acc[curr.name] = curr;
464
488
  return acc;
465
- });
489
+ }, {});
466
490
  const components = {
467
- ...autoGeneratedComponents,
491
+ ...processed,
468
492
  Lunchbox: LunchboxWrapper,
469
493
  };
470
494
 
@@ -628,7 +652,6 @@
628
652
  // register click, pointerdown, pointerup
629
653
  if (key === 'onClick' || key === 'onPointerDown' || key === 'onPointerUp') {
630
654
  const stop = vue.watch(() => inputActive.value, (isDown) => {
631
- console.log(isDown, currentIntersections);
632
655
  const idx = currentIntersections
633
656
  .map((v) => v.element)
634
657
  .findIndex((v) => v.instance &&
@@ -820,6 +843,12 @@
820
843
  const found = autoCreated[singleType] ||
821
844
  allNodes.find((node) => node.type?.toLowerCase() ===
822
845
  singleType.toLowerCase());
846
+ // cancel if found example is marked !isDefault
847
+ if (isMinidomNode(found) &&
848
+ (found.props['is-default'] === false ||
849
+ !found.props['isDefault'] === false)) {
850
+ return null;
851
+ }
823
852
  // if we have one, save and return
824
853
  if (found) {
825
854
  const createdAsNode = found;
@@ -951,10 +980,10 @@
951
980
  name: tag,
952
981
  render() {
953
982
  return vue.h(tag, this.$attrs, this.$slots?.default?.() || []);
954
- }
983
+ },
955
984
  });
956
985
  const extend = ({ app, ...targets }) => {
957
- Object.keys(targets).forEach(key => {
986
+ Object.keys(targets).forEach((key) => {
958
987
  app.component(key, createComponent(key));
959
988
  catalogue[key] = targets[key];
960
989
  });
@@ -1258,9 +1287,22 @@
1258
1287
  }
1259
1288
  MiniDom.RendererStandardNode = RendererStandardNode;
1260
1289
  })(MiniDom || (MiniDom = {}));
1290
+ function isMinidomNode(item) {
1291
+ return item?.minidomType === 'RendererNode';
1292
+ }
1261
1293
  const rootNode = new MiniDom.RendererRootNode();
1262
1294
  rootNode.minidomType = 'RootNode';
1263
1295
 
1296
+ const startCallbacks = [];
1297
+ const onStart = (cb, index = Infinity) => {
1298
+ if (index === Infinity) {
1299
+ startCallbacks.push(cb);
1300
+ }
1301
+ else {
1302
+ startCallbacks.splice(index, 0, cb);
1303
+ }
1304
+ };
1305
+
1264
1306
  let frameID;
1265
1307
  const beforeRender = [];
1266
1308
  const afterRender = [];
@@ -1342,8 +1384,13 @@
1342
1384
  if (isEventKey(key)) {
1343
1385
  return addEventListener({ node, key, value });
1344
1386
  }
1387
+ // update THREE property
1388
+ // get final key
1389
+ const camelKey = key.replace(/-/g, '.');
1390
+ const finalKey = propertyShortcuts[camelKey] || camelKey;
1345
1391
  // handle and return early if prop is specific to Vue/Lunchbox
1346
- if (internalLunchboxVueKeys.includes(key))
1392
+ if (internalLunchboxVueKeys.includes(key) ||
1393
+ internalLunchboxVueKeys.includes(finalKey))
1347
1394
  return node;
1348
1395
  // everything else should be Three-specific, so let's cancel if this isn't a standard node
1349
1396
  if (!isLunchboxStandardNode(node))
@@ -1358,12 +1405,8 @@
1358
1405
  // cancel if no target
1359
1406
  if (!target)
1360
1407
  return node;
1361
- // update THREE property
1362
- // get final key
1363
- const camelKey = key.replace(/-/g, '.');
1364
- let finalKey = propertyShortcuts[camelKey] || camelKey;
1365
- let liveProperty;
1366
1408
  // burrow down until we get property to change
1409
+ let liveProperty;
1367
1410
  for (let i = 0; i < nestedPropertiesToCheck.length && !liveProperty; i++) {
1368
1411
  const nestedProperty = nestedPropertiesToCheck[i];
1369
1412
  const fullPath = [nestedProperty, finalKey].filter(Boolean).join('.');
@@ -1428,6 +1471,8 @@
1428
1471
  'args',
1429
1472
  'attach',
1430
1473
  'attachArray',
1474
+ 'is.default',
1475
+ 'isDefault',
1431
1476
  'key',
1432
1477
  'onAdded',
1433
1478
  // 'onReady',
@@ -1683,9 +1728,51 @@
1683
1728
  inputActive,
1684
1729
  mousePos,
1685
1730
  };
1731
+ /** The current camera. Often easier to use `useCamera` instead of this. */
1686
1732
  const camera = vue.computed(() => ensuredCamera.value?.instance ?? null);
1733
+ /** Run a function using the current camera when it's present. */
1734
+ function useCamera(callback, once = true) {
1735
+ let destroy;
1736
+ destroy = vue.watch(camera, (newVal) => {
1737
+ if (!newVal)
1738
+ return;
1739
+ // TODO: better fix than `any`?
1740
+ callback(newVal);
1741
+ if (once) {
1742
+ destroy?.();
1743
+ }
1744
+ }, { immediate: true });
1745
+ }
1746
+ /** The current renderer. Often easier to use `useRenderer` instead of this. */
1687
1747
  const renderer = vue.computed(() => ensureRenderer.value?.instance ?? null);
1748
+ /** Run a function using the current renderer when it's present. */
1749
+ function useRenderer(callback, once = true) {
1750
+ let destroy;
1751
+ destroy = vue.watch(renderer, (newVal) => {
1752
+ if (!newVal)
1753
+ return;
1754
+ // TODO: better fix than `any`?
1755
+ callback(newVal);
1756
+ if (once) {
1757
+ destroy?.();
1758
+ }
1759
+ }, { immediate: true });
1760
+ }
1761
+ /** The current scene. Often easier to use `useScene` instead of this. */
1688
1762
  const scene = vue.computed(() => ensuredScene.value.instance);
1763
+ /** Run a function using the current scene when it's present. */
1764
+ function useScene(callback, once = true) {
1765
+ let destroy;
1766
+ destroy = vue.watch(scene, (newVal) => {
1767
+ if (!newVal)
1768
+ return;
1769
+ // TODO: better fix than `any`?
1770
+ callback(newVal);
1771
+ if (once) {
1772
+ destroy?.();
1773
+ }
1774
+ }, { immediate: true });
1775
+ }
1689
1776
  // CUSTOM RENDER SUPPORT
1690
1777
  // ====================
1691
1778
  let app = null;
@@ -1752,7 +1839,6 @@
1752
1839
  return app;
1753
1840
  };
1754
1841
 
1755
- exports.autoGeneratedComponents = autoGeneratedComponents;
1756
1842
  exports.camera = camera;
1757
1843
  exports.clearCustomRender = clearCustomRender;
1758
1844
  exports.createApp = createApp;
@@ -1762,9 +1848,13 @@
1762
1848
  exports.offBeforeRender = offBeforeRender;
1763
1849
  exports.onAfterRender = onAfterRender;
1764
1850
  exports.onBeforeRender = onBeforeRender;
1851
+ exports.onStart = onStart;
1765
1852
  exports.renderer = renderer;
1766
1853
  exports.scene = scene;
1767
1854
  exports.setCustomRender = setCustomRender;
1855
+ exports.useCamera = useCamera;
1856
+ exports.useRenderer = useRenderer;
1857
+ exports.useScene = useScene;
1768
1858
 
1769
1859
  Object.defineProperty(exports, '__esModule', { value: true });
1770
1860
 
@@ -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.autoGeneratedComponents=u,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=I.value?.instance,o=z.value.instance,a=F.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,zoom:Number},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=G(["WebGLRenderer"]),l)s.value=!1,W.value=!0;else{const t={alpha:e.transparent,antialias:!0,canvas:a.value.domElement,...e.rendererArguments??{}};I.value=v({type:"WebGLRenderer",uuid:$,props:{args:[t]}}),W.value=!0;const n=I,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=G(["PerspectiveCamera","OrthographicCamera"]),p?D.value=!0:(e.ortho||e.orthographic?F.value=v({props:{args:e.cameraArgs??[]},type:"OrthographicCamera",uuid:k}):F.value=v({props:{args:e.cameraArgs??[45,.5625,1,1e3]},type:"PerspectiveCamera",uuid:k}),D.value=!0,p=F.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(p&&void 0!==e.zoom&&(p.instance.zoom=e.zoom),m=z.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);const o=t.getCurrentInstance().appContext.app;for(let e of te)e({app:o,camera:p.instance,renderer:l.instance,scene:m.instance});ae({app:o,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={},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 J.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&&(z.value=r),r}const g=[],b=t.ref(!1);function x({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)&&(K.value,e.instance&&!g.includes(e)&&(o=e,g.push(o),e.eventListenerRemoveFunctions[n].push((()=>(e=>{const t=g.indexOf(e);-1!==t&&g.splice(t,1)})(e))))),"onClick"===n||"onPointerDown"===n||"onPointerUp"===n){const r=t.watch((()=>b.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,A,C;const E=t.ref({x:1/0,y:1/0});let L=!1;let P=[];const M=()=>{const e=K.value?.instance,t=F.value?.instance;if(!e||!t)return;e.setFromCamera(he.mousePos.value,t);const n=e.intersectObjects(g.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=g.find((t=>t.instance?.uuid===e.object.uuid));t&&o.push({element:t,intersection:e})}else{const t=g.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:g.find((t=>t.instance?.uuid===e.object.uuid)),intersection:e})));o.forEach((({element:e,intersection:t})=>{N({element:e,eventKeys:["onPointerEnter"],intersection:t})})),a.forEach((({element:e,intersection:t})=>{N({element:e,eventKeys:["onPointerOver","onPointerMove"],intersection:t})})),s.forEach((({element:e,intersection:t})=>{N({element:e,eventKeys:["onPointerLeave","onPointerOut"],intersection:t})})),P=[].concat(o,a)},N=({element:e,eventKeys:t,intersection:n})=>{e&&t.forEach((t=>{e.eventListeners[t]&&e.eventListeners[t].forEach((e=>{e({intersection:n})}))}))};function B(t={}){return e.lunchboxTree||(e.lunchboxTree=new J.RendererRootNode(t)),e.lunchboxTree}function G(e){Array.isArray(e)||(e=[e]);for(let t of e)if(O[t])return O[t];for(let n of e){const e=T[n]||s.find((e=>e.type?.toLowerCase()===n.toLowerCase()));if(!(t=e,"RendererNode"!==t?.minidomType||!1!==e.props["is-default"]&&!1!=!e.props.isDefault))return null;if(e){const t=e;return T[n]=t,t}}var t;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=G(e);if(t)return t;const a=B(),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="FALLBACK_CAMERA",S=j(["PerspectiveCamera","OrthographicCamera"],k,{args:[45,.5625,1,1e3]}),D=t.ref(!1),F=t.computed({get:()=>D.value?S.value:null,set(e){const t=e.type??"",n=t[0].toUpperCase()+t.slice(1);O[n]=e}}),$="FALLBACK_RENDERER",U=j(["WebGLRenderer"],$,{}),W=t.ref(!1),I=t.computed({get:()=>W.value?U.value:null,set(e){const t=e.type??"",n=t[0].toUpperCase()+t.slice(1);O[n]=e}}),z=j("Scene","FALLBACK_SCENE"),K=j("Raycaster","AUTO_RAYCASTER",{},(e=>(e=>{if(!e.instance)return;let n=null;n=t.watch((()=>I.value),(e=>{e?.instance&&(L||(w=t=>{const n=(e.instance.domElement.width??1)/he.dpr.value,r=(e.instance.domElement.height??1)/he.dpr.value;E.value.x=t.offsetX/n*2-1,E.value.y=-t.offsetY/r*2+1},A=()=>b.value=!0,C=()=>b.value=!1,e.instance.domElement.addEventListener("mousemove",w),e.instance.domElement.addEventListener("mousedown",A),e.instance.domElement.addEventListener("mouseup",C),se(M),L=!0),n&&n())}),{immediate:!0})})(e))),_=e=>t.defineComponent({inheritAttrs:!1,name:e,render(){return t.h(e,this.$attrs,this.$slots?.default?.()||[])}});var V,q=new Uint8Array(16);function H(){if(!V&&!(V="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 V(q)}var Y=/^(?:[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 X(e){return"string"==typeof e&&Y.test(e)}for(var J,Q=[],Z=0;Z<256;++Z)Q.push((Z+256).toString(16).substr(1));function ee(e,t,n){var r=(e=e||{}).random||(e.rng||H)();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=(Q[e[t+0]]+Q[e[t+1]]+Q[e[t+2]]+Q[e[t+3]]+"-"+Q[e[t+4]]+Q[e[t+5]]+"-"+Q[e[t+6]]+Q[e[t+7]]+"-"+Q[e[t+8]]+Q[e[t+9]]+"-"+Q[e[t+10]]+Q[e[t+11]]+Q[e[t+12]]+Q[e[t+13]]+Q[e[t+14]]+Q[e[t+15]]).toLowerCase();if(!X(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??ee(),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}(J||(J={}));(new J.RendererRootNode).minidomType="RootNode";const te=[];let ne;const re=[],oe=[],ae=e=>{ne=requestAnimationFrame((()=>ae({app:e.app,renderer:I.value?.instance,scene:z.value.instance,camera:F.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","is.default","isDefault","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(h(e)){const e=function(e={}){const t={domElement:document.createElement(e.type??"")};return new J.RendererDomNode({...t,...e,metaType:"domMeta"})}(o);return e}const a=v(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 J.RendererTextNode({...e,...t,metaType:"textMeta"})}({text:e}),createComment:e=>function(e={}){const t={text:e.text??""};return new J.RendererCommentNode({...t,...e,metaType:"commentMeta"})}({text:e}),insert:(e,t,n)=>{let r=t??B();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=z.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);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){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 x({node:e,key:t,value:n});const o=t.replace(/-/g,"."),a=ce[o]||o;if(ue.includes(t)||ue.includes(a))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 s=e.instance;if(!s)return e;let i;for(let e=0;e<de.length&&!i;e++){const t=[de[e],a].filter(Boolean).join(".");i=i=r.get(s,t)}if(i&&r.isNumber(n)&&i.setScalar)i.setScalar(n);else if(i&&i.set){const e=Array.isArray(n)?n:[n];s[a].set(...e)}else"function"==typeof i?i.bind(e.instance)(...n):void 0!==r.get(s,a,void 0)?r.set(s,a,""===n||n):console.log(`No property ${a} found on ${s}`);const c=s?.texture?.type||s?.type;if("string"==typeof c){const e=c.toLowerCase();switch(!0){case e.includes("material"):s.needsUpdate=!0;break;case e.includes("camera")&&s.updateProjectionMatrix:s.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(){}},he={dpr:t.ref(1),inputActive:b,mousePos:E},fe=t.computed((()=>F.value?.instance??null));const ye=t.computed((()=>I.value?.instance??null));const ve=t.computed((()=>z.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(p).forEach((e=>{ge.component(e,p[e])}));const{mount:n}=ge;return ge.mount=(e,...t)=>{const r=B({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,_(n)),u[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,f(e)?e?.instance:m(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.onStart=(e,t=1/0)=>{t===1/0?te.push(e):te.splice(t,0,e)},e.renderer=ye,e.scene=ve,e.setCustomRender=e=>{ge?ge.setCustomRender(e):be=e},e.useCamera=function(e,n=!0){let r;r=t.watch(fe,(t=>{t&&(e(t),n&&r?.())}),{immediate:!0})},e.useRenderer=function(e,n=!0){let r;r=t.watch(ye,(t=>{t&&(e(t),n&&r?.())}),{immediate:!0})},e.useScene=function(e,n=!0){let r;r=t.watch(ve,(t=>{t&&(e(t),n&&r?.())}),{immediate:!0})},Object.defineProperty(e,"__esModule",{value:!0})}));
@@ -90,9 +90,11 @@ 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,
97
+ zoom: Number,
96
98
  },
97
99
  setup(props, context) {
98
100
  const canvas = ref();
@@ -119,12 +121,11 @@ const LunchboxWrapper = {
119
121
  if (!renderer) {
120
122
  // build renderer args
121
123
  const rendererArgs = {
124
+ alpha: props.transparent,
122
125
  antialias: true,
123
126
  canvas: canvas.value.domElement,
127
+ ...(props.rendererArguments ?? {}),
124
128
  };
125
- if (props.transparent) {
126
- rendererArgs.alpha = true;
127
- }
128
129
  // create new renderer
129
130
  ensureRenderer.value = createNode({
130
131
  type: 'WebGLRenderer',
@@ -162,7 +163,6 @@ const LunchboxWrapper = {
162
163
  // the user has initialized the renderer, so anything depending
163
164
  // on the renderer can execute
164
165
  rendererReady.value = true;
165
- return;
166
166
  }
167
167
  // CAMERA
168
168
  // ====================
@@ -196,14 +196,21 @@ const LunchboxWrapper = {
196
196
  else {
197
197
  cameraReady.value = true;
198
198
  }
199
+ if (!camera.instance) {
200
+ throw new Error('Error creating camera.');
201
+ }
199
202
  // move camera if needed
200
203
  if (camera && props.cameraPosition) {
201
- camera.instance?.position.set(...props.cameraPosition);
204
+ camera.instance.position.set(...props.cameraPosition);
202
205
  }
203
206
  // angle camera if needed
204
207
  if (camera && (props.cameraLookAt || props.cameraLook)) {
205
208
  const source = (props.cameraLookAt || props.cameraLook);
206
- camera.instance?.lookAt(...source);
209
+ camera.instance.lookAt(...source);
210
+ }
211
+ // zoom camera if needed
212
+ if (camera && props.zoom !== undefined) {
213
+ camera.instance.zoom = props.zoom;
207
214
  }
208
215
  // SCENE
209
216
  // ====================
@@ -226,11 +233,23 @@ const LunchboxWrapper = {
226
233
  else {
227
234
  throw new Error('missing renderer');
228
235
  }
236
+ // CALLBACK PREP
237
+ // ====================
238
+ const app = getCurrentInstance().appContext.app;
239
+ // START
240
+ // ====================
241
+ for (let startCallback of startCallbacks) {
242
+ startCallback({
243
+ app,
244
+ camera: camera.instance,
245
+ renderer: renderer.instance,
246
+ scene: scene.instance,
247
+ });
248
+ }
229
249
  // KICK UPDATE
230
250
  // ====================
231
- // console.log(scene)
232
251
  update({
233
- app: getCurrentInstance().appContext.app,
252
+ app,
234
253
  camera: camera.instance,
235
254
  renderer: renderer.instance,
236
255
  scene: scene.instance,
@@ -435,15 +454,20 @@ const createComponent$1 = (tag) => defineComponent({
435
454
  inheritAttrs: false,
436
455
  name: tag,
437
456
  setup(props, context) {
438
- return () => h(tag, context.attrs, context.slots?.default?.() || []);
457
+ return () => {
458
+ return h(tag, context.attrs, context.slots?.default?.() || []);
459
+ };
439
460
  },
440
461
  });
441
- autoGeneratedComponents.map(createComponent$1).reduce((acc, curr) => {
462
+ // turn components into registered map
463
+ const processed = autoGeneratedComponents
464
+ .map(createComponent$1)
465
+ .reduce((acc, curr) => {
442
466
  acc[curr.name] = curr;
443
467
  return acc;
444
- });
468
+ }, {});
445
469
  const components = {
446
- ...autoGeneratedComponents,
470
+ ...processed,
447
471
  Lunchbox: LunchboxWrapper,
448
472
  };
449
473
 
@@ -607,7 +631,6 @@ function addEventListener({ node, key, value, }) {
607
631
  // register click, pointerdown, pointerup
608
632
  if (key === 'onClick' || key === 'onPointerDown' || key === 'onPointerUp') {
609
633
  const stop = watch(() => inputActive.value, (isDown) => {
610
- console.log(isDown, currentIntersections);
611
634
  const idx = currentIntersections
612
635
  .map((v) => v.element)
613
636
  .findIndex((v) => v.instance &&
@@ -799,6 +822,12 @@ function tryGetNodeWithInstanceType(pascalCaseTypes) {
799
822
  const found = autoCreated[singleType] ||
800
823
  allNodes.find((node) => node.type?.toLowerCase() ===
801
824
  singleType.toLowerCase());
825
+ // cancel if found example is marked !isDefault
826
+ if (isMinidomNode(found) &&
827
+ (found.props['is-default'] === false ||
828
+ !found.props['isDefault'] === false)) {
829
+ return null;
830
+ }
802
831
  // if we have one, save and return
803
832
  if (found) {
804
833
  const createdAsNode = found;
@@ -930,10 +959,10 @@ const createComponent = (tag) => defineComponent({
930
959
  name: tag,
931
960
  render() {
932
961
  return h(tag, this.$attrs, this.$slots?.default?.() || []);
933
- }
962
+ },
934
963
  });
935
964
  const extend = ({ app, ...targets }) => {
936
- Object.keys(targets).forEach(key => {
965
+ Object.keys(targets).forEach((key) => {
937
966
  app.component(key, createComponent(key));
938
967
  catalogue[key] = targets[key];
939
968
  });
@@ -1237,9 +1266,22 @@ var MiniDom;
1237
1266
  }
1238
1267
  MiniDom.RendererStandardNode = RendererStandardNode;
1239
1268
  })(MiniDom || (MiniDom = {}));
1269
+ function isMinidomNode(item) {
1270
+ return item?.minidomType === 'RendererNode';
1271
+ }
1240
1272
  const rootNode = new MiniDom.RendererRootNode();
1241
1273
  rootNode.minidomType = 'RootNode';
1242
1274
 
1275
+ const startCallbacks = [];
1276
+ const onStart = (cb, index = Infinity) => {
1277
+ if (index === Infinity) {
1278
+ startCallbacks.push(cb);
1279
+ }
1280
+ else {
1281
+ startCallbacks.splice(index, 0, cb);
1282
+ }
1283
+ };
1284
+
1243
1285
  let frameID;
1244
1286
  const beforeRender = [];
1245
1287
  const afterRender = [];
@@ -1321,8 +1363,13 @@ function updateObjectProp({ node, key, value, }) {
1321
1363
  if (isEventKey(key)) {
1322
1364
  return addEventListener({ node, key, value });
1323
1365
  }
1366
+ // update THREE property
1367
+ // get final key
1368
+ const camelKey = key.replace(/-/g, '.');
1369
+ const finalKey = propertyShortcuts[camelKey] || camelKey;
1324
1370
  // handle and return early if prop is specific to Vue/Lunchbox
1325
- if (internalLunchboxVueKeys.includes(key))
1371
+ if (internalLunchboxVueKeys.includes(key) ||
1372
+ internalLunchboxVueKeys.includes(finalKey))
1326
1373
  return node;
1327
1374
  // everything else should be Three-specific, so let's cancel if this isn't a standard node
1328
1375
  if (!isLunchboxStandardNode(node))
@@ -1337,12 +1384,8 @@ function updateObjectProp({ node, key, value, }) {
1337
1384
  // cancel if no target
1338
1385
  if (!target)
1339
1386
  return node;
1340
- // update THREE property
1341
- // get final key
1342
- const camelKey = key.replace(/-/g, '.');
1343
- let finalKey = propertyShortcuts[camelKey] || camelKey;
1344
- let liveProperty;
1345
1387
  // burrow down until we get property to change
1388
+ let liveProperty;
1346
1389
  for (let i = 0; i < nestedPropertiesToCheck.length && !liveProperty; i++) {
1347
1390
  const nestedProperty = nestedPropertiesToCheck[i];
1348
1391
  const fullPath = [nestedProperty, finalKey].filter(Boolean).join('.');
@@ -1407,6 +1450,8 @@ const internalLunchboxVueKeys = [
1407
1450
  'args',
1408
1451
  'attach',
1409
1452
  'attachArray',
1453
+ 'is.default',
1454
+ 'isDefault',
1410
1455
  'key',
1411
1456
  'onAdded',
1412
1457
  // 'onReady',
@@ -1662,9 +1707,51 @@ const globals = {
1662
1707
  inputActive,
1663
1708
  mousePos,
1664
1709
  };
1710
+ /** The current camera. Often easier to use `useCamera` instead of this. */
1665
1711
  const camera = computed(() => ensuredCamera.value?.instance ?? null);
1712
+ /** Run a function using the current camera when it's present. */
1713
+ function useCamera(callback, once = true) {
1714
+ let destroy;
1715
+ destroy = watch(camera, (newVal) => {
1716
+ if (!newVal)
1717
+ return;
1718
+ // TODO: better fix than `any`?
1719
+ callback(newVal);
1720
+ if (once) {
1721
+ destroy?.();
1722
+ }
1723
+ }, { immediate: true });
1724
+ }
1725
+ /** The current renderer. Often easier to use `useRenderer` instead of this. */
1666
1726
  const renderer = computed(() => ensureRenderer.value?.instance ?? null);
1727
+ /** Run a function using the current renderer when it's present. */
1728
+ function useRenderer(callback, once = true) {
1729
+ let destroy;
1730
+ destroy = watch(renderer, (newVal) => {
1731
+ if (!newVal)
1732
+ return;
1733
+ // TODO: better fix than `any`?
1734
+ callback(newVal);
1735
+ if (once) {
1736
+ destroy?.();
1737
+ }
1738
+ }, { immediate: true });
1739
+ }
1740
+ /** The current scene. Often easier to use `useScene` instead of this. */
1667
1741
  const scene = computed(() => ensuredScene.value.instance);
1742
+ /** Run a function using the current scene when it's present. */
1743
+ function useScene(callback, once = true) {
1744
+ let destroy;
1745
+ destroy = watch(scene, (newVal) => {
1746
+ if (!newVal)
1747
+ return;
1748
+ // TODO: better fix than `any`?
1749
+ callback(newVal);
1750
+ if (once) {
1751
+ destroy?.();
1752
+ }
1753
+ }, { immediate: true });
1754
+ }
1668
1755
  // CUSTOM RENDER SUPPORT
1669
1756
  // ====================
1670
1757
  let app = null;
@@ -1731,4 +1818,4 @@ const createApp = (root) => {
1731
1818
  return app;
1732
1819
  };
1733
1820
 
1734
- export { autoGeneratedComponents, camera, clearCustomRender, createApp, find, globals, lunchboxRootNode as lunchboxTree, offAfterRender, offBeforeRender, onAfterRender, onBeforeRender, renderer, scene, setCustomRender };
1821
+ 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-dev002",
3
+ "version": "0.1.4012",
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",
@@ -36,7 +36,7 @@
36
36
  "vue-tsc": "^0.3.0"
37
37
  },
38
38
  "peerDependencies": {
39
- "three": "^0.133.1"
39
+ "three": "0.137.5"
40
40
  },
41
41
  "files": [
42
42
  "dist",
package/src/.DS_Store ADDED
Binary file
@@ -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,9 +52,11 @@ 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,
59
+ zoom: Number,
57
60
  },
58
61
  setup(props: Lunch.WrapperProps, context) {
59
62
  const canvas = ref<MiniDom.RendererDomNode>()
@@ -82,11 +85,10 @@ export const LunchboxWrapper: ComponentOptions = {
82
85
  if (!renderer) {
83
86
  // build renderer args
84
87
  const rendererArgs: THREE.WebGLRendererParameters = {
88
+ alpha: props.transparent,
85
89
  antialias: true,
86
90
  canvas: canvas.value.domElement,
87
- }
88
- if (props.transparent) {
89
- rendererArgs.alpha = true
91
+ ...(props.rendererArguments ?? {}),
90
92
  }
91
93
 
92
94
  // create new renderer
@@ -137,7 +139,6 @@ export const LunchboxWrapper: ComponentOptions = {
137
139
  // the user has initialized the renderer, so anything depending
138
140
  // on the renderer can execute
139
141
  rendererReady.value = true
140
- return
141
142
  }
142
143
 
143
144
  // CAMERA
@@ -172,14 +173,21 @@ export const LunchboxWrapper: ComponentOptions = {
172
173
  } else {
173
174
  cameraReady.value = true
174
175
  }
176
+ if (!camera.instance) {
177
+ throw new Error('Error creating camera.')
178
+ }
175
179
  // move camera if needed
176
180
  if (camera && props.cameraPosition) {
177
- camera.instance?.position.set(...props.cameraPosition)
181
+ camera.instance.position.set(...props.cameraPosition)
178
182
  }
179
183
  // angle camera if needed
180
184
  if (camera && (props.cameraLookAt || props.cameraLook)) {
181
185
  const source = (props.cameraLookAt || props.cameraLook)!
182
- camera.instance?.lookAt(...source)
186
+ camera.instance.lookAt(...source)
187
+ }
188
+ // zoom camera if needed
189
+ if (camera && props.zoom !== undefined) {
190
+ ;(camera.instance as THREE.OrthographicCamera).zoom = props.zoom
183
191
  }
184
192
 
185
193
  // SCENE
@@ -209,11 +217,25 @@ export const LunchboxWrapper: ComponentOptions = {
209
217
  throw new Error('missing renderer')
210
218
  }
211
219
 
220
+ // CALLBACK PREP
221
+ // ====================
222
+ const app = getCurrentInstance()!.appContext.app as Lunch.App
223
+
224
+ // START
225
+ // ====================
226
+ for (let startCallback of startCallbacks) {
227
+ startCallback({
228
+ app,
229
+ camera: camera.instance,
230
+ renderer: renderer.instance,
231
+ scene: scene.instance,
232
+ })
233
+ }
234
+
212
235
  // KICK UPDATE
213
236
  // ====================
214
- // console.log(scene)
215
237
  update({
216
- app: getCurrentInstance()!.appContext.app as Lunch.App,
238
+ app,
217
239
  camera: camera.instance,
218
240
  renderer: renderer.instance,
219
241
  scene: scene.instance,
@@ -13,16 +13,21 @@ const createComponent = (tag: string) =>
13
13
  inheritAttrs: false,
14
14
  name: tag,
15
15
  setup(props, context) {
16
- return () => h(tag, context.attrs, context.slots?.default?.() || [])
16
+ return () => {
17
+ return h(tag, context.attrs, context.slots?.default?.() || [])
18
+ }
17
19
  },
18
20
  })
19
21
 
20
- autoGeneratedComponents.map(createComponent).reduce((acc, curr) => {
21
- ;(acc as any)[curr.name] = curr
22
- return acc
23
- })
22
+ // turn components into registered map
23
+ const processed = autoGeneratedComponents
24
+ .map(createComponent)
25
+ .reduce((acc, curr) => {
26
+ acc[curr.name] = curr
27
+ return acc
28
+ }, {} as Record<string, ReturnType<typeof defineComponent>>)
24
29
 
25
30
  export const components = {
26
- ...autoGeneratedComponents,
31
+ ...processed,
27
32
  Lunchbox: LunchboxWrapper,
28
33
  }
Binary file
@@ -1,4 +1,4 @@
1
- import { allNodes, createNode, MiniDom } from '.'
1
+ import { allNodes, createNode, isMinidomNode, MiniDom } from '.'
2
2
  import { setupAutoRaycaster } from './interaction/setupAutoRaycaster'
3
3
  import { computed, reactive, ref, WritableComputedRef } from 'vue'
4
4
  import { Lunch } from '..'
@@ -38,6 +38,15 @@ export function tryGetNodeWithInstanceType<T extends THREE.Object3D>(
38
38
  singleType.toLowerCase()
39
39
  )
40
40
 
41
+ // cancel if found example is marked !isDefault
42
+ if (
43
+ isMinidomNode(found) &&
44
+ (found.props['is-default'] === false ||
45
+ !found.props['isDefault'] === false)
46
+ ) {
47
+ return null
48
+ }
49
+
41
50
  // if we have one, save and return
42
51
  if (found) {
43
52
  const createdAsNode = found as MiniDom.RendererStandardNode<T>
@@ -8,12 +8,18 @@ const createComponent = (tag: string) =>
8
8
  name: tag,
9
9
  render() {
10
10
  return h(tag, this.$attrs, this.$slots?.default?.() || [])
11
- }
11
+ },
12
12
  })
13
13
 
14
- export const extend = ({ app, ...targets }: { app: Lunch.App, [key: string]: any }) => {
15
- Object.keys(targets).forEach(key => {
14
+ export const extend = ({
15
+ app,
16
+ ...targets
17
+ }: {
18
+ app: Lunch.App
19
+ [key: string]: any
20
+ }) => {
21
+ Object.keys(targets).forEach((key) => {
16
22
  app.component(key, createComponent(key))
17
23
  catalogue[key] = targets[key]
18
24
  })
19
- }
25
+ }
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
+ }
@@ -31,8 +31,17 @@ export function updateObjectProp({
31
31
  return addEventListener({ node, key, value })
32
32
  }
33
33
 
34
+ // update THREE property
35
+ // get final key
36
+ const camelKey = key.replace(/-/g, '.')
37
+ const finalKey = propertyShortcuts[camelKey] || camelKey
38
+
34
39
  // handle and return early if prop is specific to Vue/Lunchbox
35
- if (internalLunchboxVueKeys.includes(key)) return node
40
+ if (
41
+ internalLunchboxVueKeys.includes(key) ||
42
+ internalLunchboxVueKeys.includes(finalKey)
43
+ )
44
+ return node
36
45
 
37
46
  // everything else should be Three-specific, so let's cancel if this isn't a standard node
38
47
  if (!isLunchboxStandardNode(node)) return node
@@ -49,12 +58,8 @@ export function updateObjectProp({
49
58
  // cancel if no target
50
59
  if (!target) return node
51
60
 
52
- // update THREE property
53
- // get final key
54
- const camelKey = key.replace(/-/g, '.')
55
- let finalKey = propertyShortcuts[camelKey] || camelKey
56
- let liveProperty
57
61
  // burrow down until we get property to change
62
+ let liveProperty
58
63
  for (let i = 0; i < nestedPropertiesToCheck.length && !liveProperty; i++) {
59
64
  const nestedProperty = nestedPropertiesToCheck[i]
60
65
  const fullPath = [nestedProperty, finalKey].filter(Boolean).join('.')
@@ -128,6 +133,8 @@ const internalLunchboxVueKeys = [
128
133
  'args',
129
134
  'attach',
130
135
  'attachArray',
136
+ 'is.default',
137
+ 'isDefault',
131
138
  'key',
132
139
  'onAdded',
133
140
  // 'onReady',
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,11 +27,11 @@ 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
- export * from './components/autoGeneratedComponents'
28
35
 
29
36
  // Utilities
30
37
  export * from './utils/find'
@@ -36,9 +43,74 @@ export const globals = {
36
43
  mousePos,
37
44
  }
38
45
 
46
+ /** The current camera. Often easier to use `useCamera` instead of this. */
39
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. */
40
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. */
41
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
+ }
42
114
 
43
115
  // CUSTOM RENDER SUPPORT
44
116
  // ====================
package/src/types.ts CHANGED
@@ -145,8 +145,11 @@ 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
153
+ zoom?: number
151
154
  }
152
155
  }
@@ -23,7 +23,9 @@ export const isEventKey = (target: any): target is Lunch.EventKey => {
23
23
  ].includes(target)
24
24
  }
25
25
 
26
- export const isLunchboxComponent = (node: any): node is Lunch.LunchboxComponent => {
26
+ export const isLunchboxComponent = (
27
+ node: any
28
+ ): node is Lunch.LunchboxComponent => {
27
29
  return node?.$el && node?.$el?.hasOwnProperty?.('instance')
28
30
  }
29
31
 
@@ -35,10 +37,12 @@ export const isLunchboxDomComponent = (node: any): node is Lunch.DomMeta => {
35
37
  return lunchboxDomComponentNames.includes(typeToCheck ?? '')
36
38
  }
37
39
 
38
- export const isLunchboxStandardNode = (node: any): node is Lunch.StandardMeta => {
40
+ export const isLunchboxStandardNode = (
41
+ node: any
42
+ ): node is Lunch.StandardMeta => {
39
43
  return node?.metaType === 'standardMeta'
40
44
  }
41
45
 
42
46
  export const isLunchboxRootNode = (node: any): node is Lunch.RootMeta => {
43
47
  return node.isLunchboxRootNode
44
- }
48
+ }