lunchboxjs 0.1.4012 → 0.1.4015
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/LICENSE.md +7 -0
- package/README.md +14 -0
- package/dist/lunchboxjs.js +111 -103
- package/dist/lunchboxjs.min.js +1 -1
- package/dist/lunchboxjs.module.js +111 -104
- package/package.json +10 -5
- package/src/components/LunchboxWrapper/LunchboxWrapper.ts +31 -3
- package/src/core/createNode.ts +5 -1
- package/src/core/ensure.ts +4 -10
- package/src/index.ts +12 -40
- package/src/nodeOps/remove.ts +0 -1
- package/src/types.ts +1 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright 2022 Breakfast Studio, LLC
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
1
|
Custom Vue 3 renderer for ThreeJS.
|
|
2
2
|
|
|
3
|
+
## Full Docs
|
|
4
|
+
|
|
3
5
|
[Docs](//docs.lunchboxjs.com)
|
|
6
|
+
|
|
7
|
+
## Local Dev
|
|
8
|
+
|
|
9
|
+
`npm run dev` to run dev server. From there, edit source code in `/src/...` and examples in `/demo/...` to build and test features.
|
|
10
|
+
|
|
11
|
+
### Creating Examples
|
|
12
|
+
|
|
13
|
+
Run `npm run demo:create` to create a new demo.
|
|
14
|
+
|
|
15
|
+
## Docs Dev
|
|
16
|
+
|
|
17
|
+
`npm run docs:dev` to run docs dev. Docs exist as a Vitepress site in the `/docs` folder.
|
package/dist/lunchboxjs.js
CHANGED
|
@@ -87,6 +87,8 @@
|
|
|
87
87
|
});
|
|
88
88
|
};
|
|
89
89
|
|
|
90
|
+
// TODO:
|
|
91
|
+
// Continue r3f prop - what else (besides camera fov) makes r3f look good?
|
|
90
92
|
/** fixed & fill styling for container */
|
|
91
93
|
const fillStyle = (position) => {
|
|
92
94
|
return {
|
|
@@ -111,6 +113,7 @@
|
|
|
111
113
|
dpr: Number,
|
|
112
114
|
ortho: Boolean,
|
|
113
115
|
orthographic: Boolean,
|
|
116
|
+
r3f: Boolean,
|
|
114
117
|
rendererArguments: Object,
|
|
115
118
|
rendererProperties: Object,
|
|
116
119
|
shadow: [Boolean, Object],
|
|
@@ -125,6 +128,10 @@
|
|
|
125
128
|
let renderer;
|
|
126
129
|
let camera;
|
|
127
130
|
let scene;
|
|
131
|
+
// https://threejs.org/docs/index.html#manual/en/introduction/Color-management
|
|
132
|
+
if (props.r3f && THREE__namespace?.ColorManagement) {
|
|
133
|
+
THREE__namespace.ColorManagement.legacyMode = false;
|
|
134
|
+
}
|
|
128
135
|
// MOUNT
|
|
129
136
|
// ====================
|
|
130
137
|
vue.onMounted(() => {
|
|
@@ -145,6 +152,9 @@
|
|
|
145
152
|
alpha: props.transparent,
|
|
146
153
|
antialias: true,
|
|
147
154
|
canvas: canvas.value.domElement,
|
|
155
|
+
powerPreference: !!props.r3f
|
|
156
|
+
? 'high-performance'
|
|
157
|
+
: 'default',
|
|
148
158
|
...(props.rendererArguments ?? {}),
|
|
149
159
|
};
|
|
150
160
|
// create new renderer
|
|
@@ -158,6 +168,15 @@
|
|
|
158
168
|
// we've initialized the renderer, so anything depending on it can execute now
|
|
159
169
|
rendererReady.value = true;
|
|
160
170
|
const rendererAsWebGlRenderer = ensureRenderer;
|
|
171
|
+
// apply r3f settings if desired
|
|
172
|
+
if (props.r3f) {
|
|
173
|
+
if (rendererAsWebGlRenderer.value.instance) {
|
|
174
|
+
rendererAsWebGlRenderer.value.instance.outputEncoding =
|
|
175
|
+
THREE__namespace.sRGBEncoding;
|
|
176
|
+
rendererAsWebGlRenderer.value.instance.toneMapping =
|
|
177
|
+
THREE__namespace.ACESFilmicToneMapping;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
161
180
|
// update render sugar
|
|
162
181
|
const sugar = {
|
|
163
182
|
shadow: props.shadow,
|
|
@@ -205,7 +224,12 @@
|
|
|
205
224
|
else {
|
|
206
225
|
ensuredCamera.value = createNode({
|
|
207
226
|
props: {
|
|
208
|
-
args: props.cameraArgs ?? [
|
|
227
|
+
args: props.cameraArgs ?? [
|
|
228
|
+
props.r3f ? 75 : 45,
|
|
229
|
+
0.5625,
|
|
230
|
+
1,
|
|
231
|
+
1000,
|
|
232
|
+
],
|
|
209
233
|
},
|
|
210
234
|
type: 'PerspectiveCamera',
|
|
211
235
|
uuid: fallbackCameraUuid,
|
|
@@ -238,7 +262,7 @@
|
|
|
238
262
|
scene = ensuredScene.value;
|
|
239
263
|
// set background color
|
|
240
264
|
if (scene && scene.instance && props.background) {
|
|
241
|
-
scene.instance.background = new
|
|
265
|
+
scene.instance.background = new THREE__namespace.Color(props.background);
|
|
242
266
|
}
|
|
243
267
|
// MISC PROPERTIES
|
|
244
268
|
// ====================
|
|
@@ -544,76 +568,6 @@
|
|
|
544
568
|
return node.isLunchboxRootNode;
|
|
545
569
|
};
|
|
546
570
|
|
|
547
|
-
/** Create a new Lunchbox comment node. */
|
|
548
|
-
function createCommentNode(options = {}) {
|
|
549
|
-
const defaults = {
|
|
550
|
-
text: options.text ?? '',
|
|
551
|
-
};
|
|
552
|
-
return new MiniDom.RendererCommentNode({
|
|
553
|
-
...defaults,
|
|
554
|
-
...options,
|
|
555
|
-
metaType: 'commentMeta',
|
|
556
|
-
});
|
|
557
|
-
}
|
|
558
|
-
/** Create a new DOM node. */
|
|
559
|
-
function createDomNode(options = {}) {
|
|
560
|
-
const domElement = document.createElement(options.type ?? '');
|
|
561
|
-
const defaults = {
|
|
562
|
-
domElement,
|
|
563
|
-
};
|
|
564
|
-
const node = new MiniDom.RendererDomNode({
|
|
565
|
-
...defaults,
|
|
566
|
-
...options,
|
|
567
|
-
metaType: 'domMeta',
|
|
568
|
-
});
|
|
569
|
-
return node;
|
|
570
|
-
}
|
|
571
|
-
/** Create a new Lunchbox text node. */
|
|
572
|
-
function createTextNode(options = {}) {
|
|
573
|
-
const defaults = {
|
|
574
|
-
text: options.text ?? '',
|
|
575
|
-
};
|
|
576
|
-
return new MiniDom.RendererTextNode({
|
|
577
|
-
...options,
|
|
578
|
-
...defaults,
|
|
579
|
-
metaType: 'textMeta',
|
|
580
|
-
});
|
|
581
|
-
}
|
|
582
|
-
/** Create a new Lunchbox standard node. */
|
|
583
|
-
function createNode(options = {}, props = {}) {
|
|
584
|
-
const defaults = {
|
|
585
|
-
attached: options.attached ?? [],
|
|
586
|
-
attachedArray: options.attachedArray ?? {},
|
|
587
|
-
instance: options.instance ?? null,
|
|
588
|
-
};
|
|
589
|
-
const node = new MiniDom.RendererStandardNode({
|
|
590
|
-
...options,
|
|
591
|
-
...defaults,
|
|
592
|
-
metaType: 'standardMeta',
|
|
593
|
-
});
|
|
594
|
-
if (node.type && !isLunchboxRootNode(node) && !node.instance) {
|
|
595
|
-
// if (node.type.includes('Camera')) {
|
|
596
|
-
// console.log(node.type, {
|
|
597
|
-
// ...node.props,
|
|
598
|
-
// ...props,
|
|
599
|
-
// })
|
|
600
|
-
// console.trace()
|
|
601
|
-
// }
|
|
602
|
-
node.instance = instantiateThreeObject({
|
|
603
|
-
...node,
|
|
604
|
-
props: {
|
|
605
|
-
...node.props,
|
|
606
|
-
...props,
|
|
607
|
-
},
|
|
608
|
-
});
|
|
609
|
-
}
|
|
610
|
-
if (node.type === 'scene') {
|
|
611
|
-
// manually set scene override
|
|
612
|
-
ensuredScene.value = node;
|
|
613
|
-
}
|
|
614
|
-
return node;
|
|
615
|
-
}
|
|
616
|
-
|
|
617
571
|
const interactables = [];
|
|
618
572
|
const addInteractable = (target) => {
|
|
619
573
|
interactables.push(target);
|
|
@@ -939,17 +893,10 @@
|
|
|
939
893
|
overrides[pascalType] = val;
|
|
940
894
|
},
|
|
941
895
|
});
|
|
942
|
-
// export const ensuredCamera = buildEnsured<THREE.Camera>(
|
|
943
|
-
// ['PerspectiveCamera', 'OrthographicCamera'],
|
|
944
|
-
// fallbackCameraUuid,
|
|
945
|
-
// {
|
|
946
|
-
// args: [45, 0.5625, 1, 1000],
|
|
947
|
-
// }
|
|
948
|
-
// )
|
|
949
896
|
// ENSURE RENDERER
|
|
950
897
|
// ====================
|
|
951
898
|
const fallbackRendererUuid = 'FALLBACK_RENDERER';
|
|
952
|
-
const
|
|
899
|
+
const ensuredRenderer = buildEnsured(
|
|
953
900
|
// TODO: ensure support for css/svg renderers
|
|
954
901
|
['WebGLRenderer'], //, 'CSS2DRenderer', 'CSS3DRenderer', 'SVGRenderer'],
|
|
955
902
|
fallbackRendererUuid, {});
|
|
@@ -958,7 +905,7 @@
|
|
|
958
905
|
const rendererReady = vue.ref(false);
|
|
959
906
|
const ensureRenderer = vue.computed({
|
|
960
907
|
get() {
|
|
961
|
-
return (rendererReady.value ?
|
|
908
|
+
return (rendererReady.value ? ensuredRenderer.value : null);
|
|
962
909
|
},
|
|
963
910
|
set(val) {
|
|
964
911
|
const t = val.type ?? '';
|
|
@@ -975,6 +922,80 @@
|
|
|
975
922
|
// `unknown` is intentional here - we need to typecast the node since Raycaster isn't an Object3D
|
|
976
923
|
const ensuredRaycaster = buildEnsured('Raycaster', autoRaycasterUuid, {}, (node) => setupAutoRaycaster(node));
|
|
977
924
|
|
|
925
|
+
/** Create a new Lunchbox comment node. */
|
|
926
|
+
function createCommentNode(options = {}) {
|
|
927
|
+
const defaults = {
|
|
928
|
+
text: options.text ?? '',
|
|
929
|
+
};
|
|
930
|
+
return new MiniDom.RendererCommentNode({
|
|
931
|
+
...defaults,
|
|
932
|
+
...options,
|
|
933
|
+
metaType: 'commentMeta',
|
|
934
|
+
});
|
|
935
|
+
}
|
|
936
|
+
/** Create a new DOM node. */
|
|
937
|
+
function createDomNode(options = {}) {
|
|
938
|
+
const domElement = document.createElement(options.type ?? '');
|
|
939
|
+
const defaults = {
|
|
940
|
+
domElement,
|
|
941
|
+
};
|
|
942
|
+
const node = new MiniDom.RendererDomNode({
|
|
943
|
+
...defaults,
|
|
944
|
+
...options,
|
|
945
|
+
metaType: 'domMeta',
|
|
946
|
+
});
|
|
947
|
+
return node;
|
|
948
|
+
}
|
|
949
|
+
/** Create a new Lunchbox text node. */
|
|
950
|
+
function createTextNode(options = {}) {
|
|
951
|
+
const defaults = {
|
|
952
|
+
text: options.text ?? '',
|
|
953
|
+
};
|
|
954
|
+
return new MiniDom.RendererTextNode({
|
|
955
|
+
...options,
|
|
956
|
+
...defaults,
|
|
957
|
+
metaType: 'textMeta',
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
/** Create a new Lunchbox standard node. */
|
|
961
|
+
function createNode(options = {}, props = {}) {
|
|
962
|
+
const defaults = {
|
|
963
|
+
attached: options.attached ?? [],
|
|
964
|
+
attachedArray: options.attachedArray ?? {},
|
|
965
|
+
instance: options.instance ?? null,
|
|
966
|
+
};
|
|
967
|
+
const node = new MiniDom.RendererStandardNode({
|
|
968
|
+
...options,
|
|
969
|
+
...defaults,
|
|
970
|
+
metaType: 'standardMeta',
|
|
971
|
+
});
|
|
972
|
+
if (node.type && !isLunchboxRootNode(node) && !node.instance) {
|
|
973
|
+
// if (node.type.includes('Camera')) {
|
|
974
|
+
// console.log(node.type, {
|
|
975
|
+
// ...node.props,
|
|
976
|
+
// ...props,
|
|
977
|
+
// })
|
|
978
|
+
// console.trace()
|
|
979
|
+
// }
|
|
980
|
+
node.instance = instantiateThreeObject({
|
|
981
|
+
...node,
|
|
982
|
+
props: {
|
|
983
|
+
...node.props,
|
|
984
|
+
...props,
|
|
985
|
+
},
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
// TODO: these manual overrides are a bit brittle - replace?
|
|
989
|
+
if (node.type?.toLowerCase() === 'scene') {
|
|
990
|
+
// manually set scene override
|
|
991
|
+
ensuredScene.value = node;
|
|
992
|
+
}
|
|
993
|
+
else if (node.type?.toLowerCase().endsWith('camera')) {
|
|
994
|
+
ensuredCamera.value = node;
|
|
995
|
+
}
|
|
996
|
+
return node;
|
|
997
|
+
}
|
|
998
|
+
|
|
978
999
|
const createComponent = (tag) => vue.defineComponent({
|
|
979
1000
|
inheritAttrs: false,
|
|
980
1001
|
name: tag,
|
|
@@ -1731,46 +1752,31 @@
|
|
|
1731
1752
|
/** The current camera. Often easier to use `useCamera` instead of this. */
|
|
1732
1753
|
const camera = vue.computed(() => ensuredCamera.value?.instance ?? null);
|
|
1733
1754
|
/** Run a function using the current camera when it's present. */
|
|
1734
|
-
function useCamera(callback
|
|
1735
|
-
|
|
1736
|
-
destroy = vue.watch(camera, (newVal) => {
|
|
1755
|
+
function useCamera(callback) {
|
|
1756
|
+
return vue.watch(camera, (newVal) => {
|
|
1737
1757
|
if (!newVal)
|
|
1738
1758
|
return;
|
|
1739
|
-
// TODO: better fix than `any`?
|
|
1740
1759
|
callback(newVal);
|
|
1741
|
-
if (once) {
|
|
1742
|
-
destroy?.();
|
|
1743
|
-
}
|
|
1744
1760
|
}, { immediate: true });
|
|
1745
1761
|
}
|
|
1746
1762
|
/** The current renderer. Often easier to use `useRenderer` instead of this. */
|
|
1747
1763
|
const renderer = vue.computed(() => ensureRenderer.value?.instance ?? null);
|
|
1748
1764
|
/** Run a function using the current renderer when it's present. */
|
|
1749
|
-
function useRenderer(callback
|
|
1750
|
-
|
|
1751
|
-
destroy = vue.watch(renderer, (newVal) => {
|
|
1765
|
+
function useRenderer(callback) {
|
|
1766
|
+
return vue.watch(renderer, (newVal) => {
|
|
1752
1767
|
if (!newVal)
|
|
1753
1768
|
return;
|
|
1754
|
-
// TODO: better fix than `any`?
|
|
1755
1769
|
callback(newVal);
|
|
1756
|
-
if (once) {
|
|
1757
|
-
destroy?.();
|
|
1758
|
-
}
|
|
1759
1770
|
}, { immediate: true });
|
|
1760
1771
|
}
|
|
1761
1772
|
/** The current scene. Often easier to use `useScene` instead of this. */
|
|
1762
1773
|
const scene = vue.computed(() => ensuredScene.value.instance);
|
|
1763
1774
|
/** Run a function using the current scene when it's present. */
|
|
1764
|
-
function useScene(callback
|
|
1765
|
-
|
|
1766
|
-
destroy = vue.watch(scene, (newVal) => {
|
|
1775
|
+
function useScene(callback) {
|
|
1776
|
+
return vue.watch(scene, (newVal) => {
|
|
1767
1777
|
if (!newVal)
|
|
1768
1778
|
return;
|
|
1769
|
-
// TODO: better fix than `any`?
|
|
1770
1779
|
callback(newVal);
|
|
1771
|
-
if (once) {
|
|
1772
|
-
destroy?.();
|
|
1773
|
-
}
|
|
1774
1780
|
}, { immediate: true });
|
|
1775
1781
|
}
|
|
1776
1782
|
// CUSTOM RENDER SUPPORT
|
|
@@ -1799,12 +1805,14 @@
|
|
|
1799
1805
|
app = vue.createRenderer(nodeOps).createApp(root);
|
|
1800
1806
|
// register all components
|
|
1801
1807
|
Object.keys(components).forEach((key) => {
|
|
1802
|
-
app
|
|
1808
|
+
app?.component(key, components[key]);
|
|
1803
1809
|
});
|
|
1804
1810
|
// update mount function to match Lunchbox.Node
|
|
1805
1811
|
const { mount } = app;
|
|
1806
1812
|
app.mount = (root, ...args) => {
|
|
1813
|
+
// find DOM element to use as app root
|
|
1807
1814
|
const domElement = (typeof root === 'string' ? document.querySelector(root) : root);
|
|
1815
|
+
// create or find root node
|
|
1808
1816
|
const rootNode = ensureRootNode({
|
|
1809
1817
|
domElement,
|
|
1810
1818
|
isLunchboxRootNode: true,
|
package/dist/lunchboxjs.min.js
CHANGED
|
@@ -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=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})}));
|
|
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=W.value?.instance,o=I.value.instance,a=D.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,r3f:Boolean,rendererArguments:Object,rendererProperties:Object,shadow:[Boolean,Object],transparent:Boolean,zoom:Number},setup(e,n){const o=t.ref(),s=t.ref(!0),d=t.ref(e.dpr??-1),u=t.ref();let l,p,m;return e.r3f&&a?.ColorManagement&&(a.ColorManagement.legacyMode=!1),t.onMounted((()=>{if(!o.value)throw new Error("missing canvas");if(l=N(["WebGLRenderer"]),l)s.value=!1,U.value=!0;else{const t={alpha:e.transparent,antialias:!0,canvas:o.value.domElement,powerPreference:e.r3f?"high-performance":"default",...e.rendererArguments??{}};W.value=K({type:"WebGLRenderer",uuid:F,props:{args:[t]}}),U.value=!0;const n=W;e.r3f&&n.value.instance&&(n.value.instance.outputEncoding=a.sRGBEncoding,n.value.instance.toneMapping=a.ACESFilmicToneMapping);const s={shadow:e.shadow};n.value.instance&&s?.shadow&&(n.value.instance.shadowMap.enabled=!0,"object"==typeof s.shadow&&(n.value.instance.shadowMap.type=s.shadow.type)),e.rendererProperties&&Object.keys(e.rendererProperties).forEach((t=>{r.set(n.value,t,e.rendererProperties[t])})),l=n.value}if(p=N(["PerspectiveCamera","OrthographicCamera"]),p?S.value=!0:(e.ortho||e.orthographic?D.value=K({props:{args:e.cameraArgs??[]},type:"OrthographicCamera",uuid:j}):D.value=K({props:{args:e.cameraArgs??[e.r3f?75:45,.5625,1,1e3]},type:"PerspectiveCamera",uuid:j}),S.value=!0,p=D.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=I.value,m&&m.instance&&e.background&&(m.instance.background=new a.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 n=t.getCurrentInstance().appContext.app;for(let e of te)e({app:n,camera:p.instance,renderer:l.instance,scene:m.instance});ae({app:n,camera:p.instance,renderer:l.instance,scene:m.instance})})),t.onBeforeUnmount((()=>{ie()})),()=>[n.slots.default?.()??null,t.h("div",{style:c("absolute"),ref:u},[s.value?t.h("canvas",{style:c("fixed"),class:"lunchbox-canvas",ref:o}):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,v=[],g=t.ref(!1);function b({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),x.includes(n)&&(z.value,e.instance&&!v.includes(e)&&(o=e,v.push(o),e.eventListenerRemoveFunctions[n].push((()=>(e=>{const t=v.indexOf(e);-1!==t&&v.splice(t,1)})(e))))),"onClick"===n||"onPointerDown"===n||"onPointerUp"===n){const r=t.watch((()=>g.value),(t=>{const r=L.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:L[r].intersection})})))}));e.eventListenerRemoveFunctions[n].push(r)}return e}const x=["onClick","onPointerUp","onPointerDown","onPointerOver","onPointerOut","onPointerEnter","onPointerLeave","onPointerMove"];let R,w,A;const C=t.ref({x:1/0,y:1/0});let E=!1;let L=[];const P=()=>{const e=z.value?.instance,t=D.value?.instance;if(!e||!t)return;e.setFromCamera(he.mousePos.value,t);const n=e.intersectObjects(v.map((e=>e.instance)));let r=[],o=[],a=[];r=L.map((e=>e.intersection)),n?.forEach((e=>{if(-1===L.findIndex((t=>t.intersection.object===e.object))){const t=v.find((t=>t.instance?.uuid===e.object.uuid));t&&o.push({element:t,intersection:e})}else{const t=v.find((t=>t.instance?.uuid===e.object.uuid));t&&a.push({element:t,intersection:e})}const t=r.findIndex((t=>t.object.uuid===e.object.uuid));-1!==t&&r.splice(t,1)}));const s=r.map((e=>({element:v.find((t=>t.instance?.uuid===e.object.uuid)),intersection:e})));o.forEach((({element:e,intersection:t})=>{M({element:e,eventKeys:["onPointerEnter"],intersection:t})})),a.forEach((({element:e,intersection:t})=>{M({element:e,eventKeys:["onPointerOver","onPointerMove"],intersection:t})})),s.forEach((({element:e,intersection:t})=>{M({element:e,eventKeys:["onPointerLeave","onPointerOut"],intersection:t})})),L=[].concat(o,a)},M=({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 N(e){Array.isArray(e)||(e=[e]);for(let t of e)if(T[t])return T[t];for(let n of e){const e=G[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 G[n]=t,t}}var t;return null}e.lunchboxTree=void 0;const G=t.reactive({}),T=t.reactive({});function O(e,n,r={},o=null){Array.isArray(e)||(e=[e]);for(let t of e)G[t]||(G[t]=null),T[t]||(T[t]=null);return t.computed({get(){const t=N(e);if(t)return t;const a=B(),s=K({type:e[0],uuid:n,props:r});return a.addChild(s),G[e[0]]=s,o&&o(s),s},set(e){const t=e.type??"",n=t[0].toUpperCase()+t.slice(1);T[n]=e}})}const j="FALLBACK_CAMERA",k=O(["PerspectiveCamera","OrthographicCamera"],j,{args:[45,.5625,1,1e3]}),S=t.ref(!1),D=t.computed({get:()=>S.value?k.value:null,set(e){const t=e.type??"",n=t[0].toUpperCase()+t.slice(1);T[n]=e}}),F="FALLBACK_RENDERER",$=O(["WebGLRenderer"],F,{}),U=t.ref(!1),W=t.computed({get:()=>U.value?$.value:null,set(e){const t=e.type??"",n=t[0].toUpperCase()+t.slice(1);T[n]=e}}),I=O("Scene","FALLBACK_SCENE"),z=O("Raycaster","AUTO_RAYCASTER",{},(e=>(e=>{if(!e.instance)return;let n=null;n=t.watch((()=>W.value),(e=>{e?.instance&&(E||(R=t=>{const n=(e.instance.domElement.width??1)/he.dpr.value,r=(e.instance.domElement.height??1)/he.dpr.value;C.value.x=t.offsetX/n*2-1,C.value.y=-t.offsetY/r*2+1},w=()=>g.value=!0,A=()=>g.value=!1,e.instance.domElement.addEventListener("mousemove",R),e.instance.domElement.addEventListener("mousedown",w),e.instance.domElement.addEventListener("mouseup",A),se(P),E=!0),n&&n())}),{immediate:!0})})(e)));function K(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?.toLowerCase()?I.value=r:r.type?.toLowerCase().endsWith("camera")&&(D.value=r),r}const _=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:W.value?.instance,scene:I.value.instance,camera:D.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=K(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=I.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 b({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(T),n=[];e.walk((e=>(n.push(e),!0))),n.forEach((e=>{const n=t.find((t=>T[t]?.uuid===e.uuid));if(n&&(T[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:g,mousePos:C},fe=t.computed((()=>D.value?.instance??null));const ye=t.computed((()=>W.value?.instance??null));const ve=t.computed((()=>I.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){return t.watch(fe,(t=>{t&&e(t)}),{immediate:!0})},e.useRenderer=function(e){return t.watch(ye,(t=>{t&&e(t)}),{immediate:!0})},e.useScene=function(e){return t.watch(ve,(t=>{t&&e(t)}),{immediate:!0})},Object.defineProperty(e,"__esModule",{value:!0})}));
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { toRaw, ref, onMounted, getCurrentInstance, onBeforeUnmount, h, defineComponent, isRef, isVNode, watch, reactive, computed, createRenderer } from 'vue';
|
|
2
2
|
import * as THREE from 'three';
|
|
3
|
-
import { Color } from 'three';
|
|
4
3
|
import { set, get, isNumber } from 'lodash';
|
|
5
4
|
|
|
6
5
|
// this needs to be in a separate file to ensure it's created immediately
|
|
@@ -66,6 +65,8 @@ const prepCanvas = (container, canvasElement, onBeforeUnmount) => {
|
|
|
66
65
|
});
|
|
67
66
|
};
|
|
68
67
|
|
|
68
|
+
// TODO:
|
|
69
|
+
// Continue r3f prop - what else (besides camera fov) makes r3f look good?
|
|
69
70
|
/** fixed & fill styling for container */
|
|
70
71
|
const fillStyle = (position) => {
|
|
71
72
|
return {
|
|
@@ -90,6 +91,7 @@ const LunchboxWrapper = {
|
|
|
90
91
|
dpr: Number,
|
|
91
92
|
ortho: Boolean,
|
|
92
93
|
orthographic: Boolean,
|
|
94
|
+
r3f: Boolean,
|
|
93
95
|
rendererArguments: Object,
|
|
94
96
|
rendererProperties: Object,
|
|
95
97
|
shadow: [Boolean, Object],
|
|
@@ -104,6 +106,10 @@ const LunchboxWrapper = {
|
|
|
104
106
|
let renderer;
|
|
105
107
|
let camera;
|
|
106
108
|
let scene;
|
|
109
|
+
// https://threejs.org/docs/index.html#manual/en/introduction/Color-management
|
|
110
|
+
if (props.r3f && THREE?.ColorManagement) {
|
|
111
|
+
THREE.ColorManagement.legacyMode = false;
|
|
112
|
+
}
|
|
107
113
|
// MOUNT
|
|
108
114
|
// ====================
|
|
109
115
|
onMounted(() => {
|
|
@@ -124,6 +130,9 @@ const LunchboxWrapper = {
|
|
|
124
130
|
alpha: props.transparent,
|
|
125
131
|
antialias: true,
|
|
126
132
|
canvas: canvas.value.domElement,
|
|
133
|
+
powerPreference: !!props.r3f
|
|
134
|
+
? 'high-performance'
|
|
135
|
+
: 'default',
|
|
127
136
|
...(props.rendererArguments ?? {}),
|
|
128
137
|
};
|
|
129
138
|
// create new renderer
|
|
@@ -137,6 +146,15 @@ const LunchboxWrapper = {
|
|
|
137
146
|
// we've initialized the renderer, so anything depending on it can execute now
|
|
138
147
|
rendererReady.value = true;
|
|
139
148
|
const rendererAsWebGlRenderer = ensureRenderer;
|
|
149
|
+
// apply r3f settings if desired
|
|
150
|
+
if (props.r3f) {
|
|
151
|
+
if (rendererAsWebGlRenderer.value.instance) {
|
|
152
|
+
rendererAsWebGlRenderer.value.instance.outputEncoding =
|
|
153
|
+
THREE.sRGBEncoding;
|
|
154
|
+
rendererAsWebGlRenderer.value.instance.toneMapping =
|
|
155
|
+
THREE.ACESFilmicToneMapping;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
140
158
|
// update render sugar
|
|
141
159
|
const sugar = {
|
|
142
160
|
shadow: props.shadow,
|
|
@@ -184,7 +202,12 @@ const LunchboxWrapper = {
|
|
|
184
202
|
else {
|
|
185
203
|
ensuredCamera.value = createNode({
|
|
186
204
|
props: {
|
|
187
|
-
args: props.cameraArgs ?? [
|
|
205
|
+
args: props.cameraArgs ?? [
|
|
206
|
+
props.r3f ? 75 : 45,
|
|
207
|
+
0.5625,
|
|
208
|
+
1,
|
|
209
|
+
1000,
|
|
210
|
+
],
|
|
188
211
|
},
|
|
189
212
|
type: 'PerspectiveCamera',
|
|
190
213
|
uuid: fallbackCameraUuid,
|
|
@@ -217,7 +240,7 @@ const LunchboxWrapper = {
|
|
|
217
240
|
scene = ensuredScene.value;
|
|
218
241
|
// set background color
|
|
219
242
|
if (scene && scene.instance && props.background) {
|
|
220
|
-
scene.instance.background = new Color(props.background);
|
|
243
|
+
scene.instance.background = new THREE.Color(props.background);
|
|
221
244
|
}
|
|
222
245
|
// MISC PROPERTIES
|
|
223
246
|
// ====================
|
|
@@ -523,76 +546,6 @@ const isLunchboxRootNode = (node) => {
|
|
|
523
546
|
return node.isLunchboxRootNode;
|
|
524
547
|
};
|
|
525
548
|
|
|
526
|
-
/** Create a new Lunchbox comment node. */
|
|
527
|
-
function createCommentNode(options = {}) {
|
|
528
|
-
const defaults = {
|
|
529
|
-
text: options.text ?? '',
|
|
530
|
-
};
|
|
531
|
-
return new MiniDom.RendererCommentNode({
|
|
532
|
-
...defaults,
|
|
533
|
-
...options,
|
|
534
|
-
metaType: 'commentMeta',
|
|
535
|
-
});
|
|
536
|
-
}
|
|
537
|
-
/** Create a new DOM node. */
|
|
538
|
-
function createDomNode(options = {}) {
|
|
539
|
-
const domElement = document.createElement(options.type ?? '');
|
|
540
|
-
const defaults = {
|
|
541
|
-
domElement,
|
|
542
|
-
};
|
|
543
|
-
const node = new MiniDom.RendererDomNode({
|
|
544
|
-
...defaults,
|
|
545
|
-
...options,
|
|
546
|
-
metaType: 'domMeta',
|
|
547
|
-
});
|
|
548
|
-
return node;
|
|
549
|
-
}
|
|
550
|
-
/** Create a new Lunchbox text node. */
|
|
551
|
-
function createTextNode(options = {}) {
|
|
552
|
-
const defaults = {
|
|
553
|
-
text: options.text ?? '',
|
|
554
|
-
};
|
|
555
|
-
return new MiniDom.RendererTextNode({
|
|
556
|
-
...options,
|
|
557
|
-
...defaults,
|
|
558
|
-
metaType: 'textMeta',
|
|
559
|
-
});
|
|
560
|
-
}
|
|
561
|
-
/** Create a new Lunchbox standard node. */
|
|
562
|
-
function createNode(options = {}, props = {}) {
|
|
563
|
-
const defaults = {
|
|
564
|
-
attached: options.attached ?? [],
|
|
565
|
-
attachedArray: options.attachedArray ?? {},
|
|
566
|
-
instance: options.instance ?? null,
|
|
567
|
-
};
|
|
568
|
-
const node = new MiniDom.RendererStandardNode({
|
|
569
|
-
...options,
|
|
570
|
-
...defaults,
|
|
571
|
-
metaType: 'standardMeta',
|
|
572
|
-
});
|
|
573
|
-
if (node.type && !isLunchboxRootNode(node) && !node.instance) {
|
|
574
|
-
// if (node.type.includes('Camera')) {
|
|
575
|
-
// console.log(node.type, {
|
|
576
|
-
// ...node.props,
|
|
577
|
-
// ...props,
|
|
578
|
-
// })
|
|
579
|
-
// console.trace()
|
|
580
|
-
// }
|
|
581
|
-
node.instance = instantiateThreeObject({
|
|
582
|
-
...node,
|
|
583
|
-
props: {
|
|
584
|
-
...node.props,
|
|
585
|
-
...props,
|
|
586
|
-
},
|
|
587
|
-
});
|
|
588
|
-
}
|
|
589
|
-
if (node.type === 'scene') {
|
|
590
|
-
// manually set scene override
|
|
591
|
-
ensuredScene.value = node;
|
|
592
|
-
}
|
|
593
|
-
return node;
|
|
594
|
-
}
|
|
595
|
-
|
|
596
549
|
const interactables = [];
|
|
597
550
|
const addInteractable = (target) => {
|
|
598
551
|
interactables.push(target);
|
|
@@ -918,17 +871,10 @@ const ensuredCamera = computed({
|
|
|
918
871
|
overrides[pascalType] = val;
|
|
919
872
|
},
|
|
920
873
|
});
|
|
921
|
-
// export const ensuredCamera = buildEnsured<THREE.Camera>(
|
|
922
|
-
// ['PerspectiveCamera', 'OrthographicCamera'],
|
|
923
|
-
// fallbackCameraUuid,
|
|
924
|
-
// {
|
|
925
|
-
// args: [45, 0.5625, 1, 1000],
|
|
926
|
-
// }
|
|
927
|
-
// )
|
|
928
874
|
// ENSURE RENDERER
|
|
929
875
|
// ====================
|
|
930
876
|
const fallbackRendererUuid = 'FALLBACK_RENDERER';
|
|
931
|
-
const
|
|
877
|
+
const ensuredRenderer = buildEnsured(
|
|
932
878
|
// TODO: ensure support for css/svg renderers
|
|
933
879
|
['WebGLRenderer'], //, 'CSS2DRenderer', 'CSS3DRenderer', 'SVGRenderer'],
|
|
934
880
|
fallbackRendererUuid, {});
|
|
@@ -937,7 +883,7 @@ fallbackRendererUuid, {});
|
|
|
937
883
|
const rendererReady = ref(false);
|
|
938
884
|
const ensureRenderer = computed({
|
|
939
885
|
get() {
|
|
940
|
-
return (rendererReady.value ?
|
|
886
|
+
return (rendererReady.value ? ensuredRenderer.value : null);
|
|
941
887
|
},
|
|
942
888
|
set(val) {
|
|
943
889
|
const t = val.type ?? '';
|
|
@@ -954,6 +900,80 @@ const autoRaycasterUuid = 'AUTO_RAYCASTER';
|
|
|
954
900
|
// `unknown` is intentional here - we need to typecast the node since Raycaster isn't an Object3D
|
|
955
901
|
const ensuredRaycaster = buildEnsured('Raycaster', autoRaycasterUuid, {}, (node) => setupAutoRaycaster(node));
|
|
956
902
|
|
|
903
|
+
/** Create a new Lunchbox comment node. */
|
|
904
|
+
function createCommentNode(options = {}) {
|
|
905
|
+
const defaults = {
|
|
906
|
+
text: options.text ?? '',
|
|
907
|
+
};
|
|
908
|
+
return new MiniDom.RendererCommentNode({
|
|
909
|
+
...defaults,
|
|
910
|
+
...options,
|
|
911
|
+
metaType: 'commentMeta',
|
|
912
|
+
});
|
|
913
|
+
}
|
|
914
|
+
/** Create a new DOM node. */
|
|
915
|
+
function createDomNode(options = {}) {
|
|
916
|
+
const domElement = document.createElement(options.type ?? '');
|
|
917
|
+
const defaults = {
|
|
918
|
+
domElement,
|
|
919
|
+
};
|
|
920
|
+
const node = new MiniDom.RendererDomNode({
|
|
921
|
+
...defaults,
|
|
922
|
+
...options,
|
|
923
|
+
metaType: 'domMeta',
|
|
924
|
+
});
|
|
925
|
+
return node;
|
|
926
|
+
}
|
|
927
|
+
/** Create a new Lunchbox text node. */
|
|
928
|
+
function createTextNode(options = {}) {
|
|
929
|
+
const defaults = {
|
|
930
|
+
text: options.text ?? '',
|
|
931
|
+
};
|
|
932
|
+
return new MiniDom.RendererTextNode({
|
|
933
|
+
...options,
|
|
934
|
+
...defaults,
|
|
935
|
+
metaType: 'textMeta',
|
|
936
|
+
});
|
|
937
|
+
}
|
|
938
|
+
/** Create a new Lunchbox standard node. */
|
|
939
|
+
function createNode(options = {}, props = {}) {
|
|
940
|
+
const defaults = {
|
|
941
|
+
attached: options.attached ?? [],
|
|
942
|
+
attachedArray: options.attachedArray ?? {},
|
|
943
|
+
instance: options.instance ?? null,
|
|
944
|
+
};
|
|
945
|
+
const node = new MiniDom.RendererStandardNode({
|
|
946
|
+
...options,
|
|
947
|
+
...defaults,
|
|
948
|
+
metaType: 'standardMeta',
|
|
949
|
+
});
|
|
950
|
+
if (node.type && !isLunchboxRootNode(node) && !node.instance) {
|
|
951
|
+
// if (node.type.includes('Camera')) {
|
|
952
|
+
// console.log(node.type, {
|
|
953
|
+
// ...node.props,
|
|
954
|
+
// ...props,
|
|
955
|
+
// })
|
|
956
|
+
// console.trace()
|
|
957
|
+
// }
|
|
958
|
+
node.instance = instantiateThreeObject({
|
|
959
|
+
...node,
|
|
960
|
+
props: {
|
|
961
|
+
...node.props,
|
|
962
|
+
...props,
|
|
963
|
+
},
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
// TODO: these manual overrides are a bit brittle - replace?
|
|
967
|
+
if (node.type?.toLowerCase() === 'scene') {
|
|
968
|
+
// manually set scene override
|
|
969
|
+
ensuredScene.value = node;
|
|
970
|
+
}
|
|
971
|
+
else if (node.type?.toLowerCase().endsWith('camera')) {
|
|
972
|
+
ensuredCamera.value = node;
|
|
973
|
+
}
|
|
974
|
+
return node;
|
|
975
|
+
}
|
|
976
|
+
|
|
957
977
|
const createComponent = (tag) => defineComponent({
|
|
958
978
|
inheritAttrs: false,
|
|
959
979
|
name: tag,
|
|
@@ -1710,46 +1730,31 @@ const globals = {
|
|
|
1710
1730
|
/** The current camera. Often easier to use `useCamera` instead of this. */
|
|
1711
1731
|
const camera = computed(() => ensuredCamera.value?.instance ?? null);
|
|
1712
1732
|
/** Run a function using the current camera when it's present. */
|
|
1713
|
-
function useCamera(callback
|
|
1714
|
-
|
|
1715
|
-
destroy = watch(camera, (newVal) => {
|
|
1733
|
+
function useCamera(callback) {
|
|
1734
|
+
return watch(camera, (newVal) => {
|
|
1716
1735
|
if (!newVal)
|
|
1717
1736
|
return;
|
|
1718
|
-
// TODO: better fix than `any`?
|
|
1719
1737
|
callback(newVal);
|
|
1720
|
-
if (once) {
|
|
1721
|
-
destroy?.();
|
|
1722
|
-
}
|
|
1723
1738
|
}, { immediate: true });
|
|
1724
1739
|
}
|
|
1725
1740
|
/** The current renderer. Often easier to use `useRenderer` instead of this. */
|
|
1726
1741
|
const renderer = computed(() => ensureRenderer.value?.instance ?? null);
|
|
1727
1742
|
/** Run a function using the current renderer when it's present. */
|
|
1728
|
-
function useRenderer(callback
|
|
1729
|
-
|
|
1730
|
-
destroy = watch(renderer, (newVal) => {
|
|
1743
|
+
function useRenderer(callback) {
|
|
1744
|
+
return watch(renderer, (newVal) => {
|
|
1731
1745
|
if (!newVal)
|
|
1732
1746
|
return;
|
|
1733
|
-
// TODO: better fix than `any`?
|
|
1734
1747
|
callback(newVal);
|
|
1735
|
-
if (once) {
|
|
1736
|
-
destroy?.();
|
|
1737
|
-
}
|
|
1738
1748
|
}, { immediate: true });
|
|
1739
1749
|
}
|
|
1740
1750
|
/** The current scene. Often easier to use `useScene` instead of this. */
|
|
1741
1751
|
const scene = computed(() => ensuredScene.value.instance);
|
|
1742
1752
|
/** Run a function using the current scene when it's present. */
|
|
1743
|
-
function useScene(callback
|
|
1744
|
-
|
|
1745
|
-
destroy = watch(scene, (newVal) => {
|
|
1753
|
+
function useScene(callback) {
|
|
1754
|
+
return watch(scene, (newVal) => {
|
|
1746
1755
|
if (!newVal)
|
|
1747
1756
|
return;
|
|
1748
|
-
// TODO: better fix than `any`?
|
|
1749
1757
|
callback(newVal);
|
|
1750
|
-
if (once) {
|
|
1751
|
-
destroy?.();
|
|
1752
|
-
}
|
|
1753
1758
|
}, { immediate: true });
|
|
1754
1759
|
}
|
|
1755
1760
|
// CUSTOM RENDER SUPPORT
|
|
@@ -1778,12 +1783,14 @@ const createApp = (root) => {
|
|
|
1778
1783
|
app = createRenderer(nodeOps).createApp(root);
|
|
1779
1784
|
// register all components
|
|
1780
1785
|
Object.keys(components).forEach((key) => {
|
|
1781
|
-
app
|
|
1786
|
+
app?.component(key, components[key]);
|
|
1782
1787
|
});
|
|
1783
1788
|
// update mount function to match Lunchbox.Node
|
|
1784
1789
|
const { mount } = app;
|
|
1785
1790
|
app.mount = (root, ...args) => {
|
|
1791
|
+
// find DOM element to use as app root
|
|
1786
1792
|
const domElement = (typeof root === 'string' ? document.querySelector(root) : root);
|
|
1793
|
+
// create or find root node
|
|
1787
1794
|
const rootNode = ensureRootNode({
|
|
1788
1795
|
domElement,
|
|
1789
1796
|
isLunchboxRootNode: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lunchboxjs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4015",
|
|
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",
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
"prepare": "npm run build:lib",
|
|
12
12
|
"docs:dev": "vitepress dev docs",
|
|
13
13
|
"docs:build": "vitepress build docs",
|
|
14
|
-
"docs:serve": "vitepress serve docs"
|
|
14
|
+
"docs:serve": "vitepress serve docs",
|
|
15
|
+
"demo:create": "node utils/createExample"
|
|
15
16
|
},
|
|
16
17
|
"dependencies": {
|
|
17
|
-
"lodash": "4.17.21",
|
|
18
18
|
"uuid": "8.3.2",
|
|
19
19
|
"vue": "^3.2.16"
|
|
20
20
|
},
|
|
@@ -22,13 +22,18 @@
|
|
|
22
22
|
"@rollup/plugin-node-resolve": "13.0.5",
|
|
23
23
|
"@rollup/plugin-typescript": "8.3.0",
|
|
24
24
|
"@types/lodash": "4.14.175",
|
|
25
|
-
"@types/three": "0.
|
|
25
|
+
"@types/three": "0.141.0",
|
|
26
26
|
"@types/uuid": "8.3.1",
|
|
27
27
|
"@vitejs/plugin-vue": "^1.9.3",
|
|
28
28
|
"chroma-js": "2.1.2",
|
|
29
|
+
"kolorist": "1.5.1",
|
|
30
|
+
"lodash": "4.17.21",
|
|
29
31
|
"nice-color-palettes": "3.0.0",
|
|
32
|
+
"prompt": "1.3.0",
|
|
33
|
+
"prompts": "2.4.2",
|
|
30
34
|
"rollup-plugin-delete": "2.0.0",
|
|
31
35
|
"rollup-plugin-terser": "7.0.2",
|
|
36
|
+
"three": "0.141.0",
|
|
32
37
|
"typescript": "^4.4.3",
|
|
33
38
|
"vite": "^2.6.4",
|
|
34
39
|
"vite-plugin-glsl": "0.0.5",
|
|
@@ -36,7 +41,7 @@
|
|
|
36
41
|
"vue-tsc": "^0.3.0"
|
|
37
42
|
},
|
|
38
43
|
"peerDependencies": {
|
|
39
|
-
"three": "0.
|
|
44
|
+
"three": "0.141.0"
|
|
40
45
|
},
|
|
41
46
|
"files": [
|
|
42
47
|
"dist",
|
|
@@ -24,9 +24,13 @@ import {
|
|
|
24
24
|
} from '../../core'
|
|
25
25
|
import { set } from 'lodash'
|
|
26
26
|
import { globals, Lunch } from '../..'
|
|
27
|
-
import { Color, Vector2 } from 'three'
|
|
27
|
+
// import { Color, Vector2, sRGBEncoding, ACESFilmicToneMapping } from 'three'
|
|
28
|
+
import * as THREE from 'three'
|
|
28
29
|
import { prepCanvas } from './prepCanvas'
|
|
29
30
|
|
|
31
|
+
// TODO:
|
|
32
|
+
// Continue r3f prop - what else (besides camera fov) makes r3f look good?
|
|
33
|
+
|
|
30
34
|
/** fixed & fill styling for container */
|
|
31
35
|
const fillStyle = (position: string) => {
|
|
32
36
|
return {
|
|
@@ -52,6 +56,7 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
52
56
|
dpr: Number,
|
|
53
57
|
ortho: Boolean,
|
|
54
58
|
orthographic: Boolean,
|
|
59
|
+
r3f: Boolean,
|
|
55
60
|
rendererArguments: Object,
|
|
56
61
|
rendererProperties: Object,
|
|
57
62
|
shadow: [Boolean, Object],
|
|
@@ -67,6 +72,11 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
67
72
|
let camera: Lunch.Node<THREE.Camera> | null
|
|
68
73
|
let scene: MiniDom.RendererStandardNode<THREE.Scene>
|
|
69
74
|
|
|
75
|
+
// https://threejs.org/docs/index.html#manual/en/introduction/Color-management
|
|
76
|
+
if (props.r3f && (THREE as any)?.ColorManagement) {
|
|
77
|
+
;(THREE as any).ColorManagement.legacyMode = false
|
|
78
|
+
}
|
|
79
|
+
|
|
70
80
|
// MOUNT
|
|
71
81
|
// ====================
|
|
72
82
|
onMounted(() => {
|
|
@@ -88,6 +98,9 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
88
98
|
alpha: props.transparent,
|
|
89
99
|
antialias: true,
|
|
90
100
|
canvas: canvas.value.domElement,
|
|
101
|
+
powerPreference: !!props.r3f
|
|
102
|
+
? 'high-performance'
|
|
103
|
+
: 'default',
|
|
91
104
|
...(props.rendererArguments ?? {}),
|
|
92
105
|
}
|
|
93
106
|
|
|
@@ -108,6 +121,16 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
108
121
|
Lunch.Node<THREE.WebGLRenderer>
|
|
109
122
|
>
|
|
110
123
|
|
|
124
|
+
// apply r3f settings if desired
|
|
125
|
+
if (props.r3f) {
|
|
126
|
+
if (rendererAsWebGlRenderer.value.instance) {
|
|
127
|
+
rendererAsWebGlRenderer.value.instance.outputEncoding =
|
|
128
|
+
THREE.sRGBEncoding
|
|
129
|
+
rendererAsWebGlRenderer.value.instance.toneMapping =
|
|
130
|
+
THREE.ACESFilmicToneMapping
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
111
134
|
// update render sugar
|
|
112
135
|
const sugar = {
|
|
113
136
|
shadow: props.shadow,
|
|
@@ -160,7 +183,12 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
160
183
|
} else {
|
|
161
184
|
ensuredCamera.value = createNode<THREE.PerspectiveCamera>({
|
|
162
185
|
props: {
|
|
163
|
-
args: props.cameraArgs ?? [
|
|
186
|
+
args: props.cameraArgs ?? [
|
|
187
|
+
props.r3f ? 75 : 45,
|
|
188
|
+
0.5625,
|
|
189
|
+
1,
|
|
190
|
+
1000,
|
|
191
|
+
],
|
|
164
192
|
},
|
|
165
193
|
type: 'PerspectiveCamera',
|
|
166
194
|
uuid: fallbackCameraUuid,
|
|
@@ -195,7 +223,7 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
195
223
|
scene = ensuredScene.value
|
|
196
224
|
// set background color
|
|
197
225
|
if (scene && scene.instance && props.background) {
|
|
198
|
-
scene.instance.background = new Color(props.background)
|
|
226
|
+
scene.instance.background = new THREE.Color(props.background)
|
|
199
227
|
}
|
|
200
228
|
|
|
201
229
|
// MISC PROPERTIES
|
package/src/core/createNode.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isLunchboxRootNode } from '../utils'
|
|
2
2
|
import { instantiateThreeObject, MiniDom, ensuredScene } from '.'
|
|
3
3
|
import { Lunch } from '..'
|
|
4
|
+
import { ensuredCamera } from './ensure'
|
|
4
5
|
|
|
5
6
|
/** Create a new Lunchbox comment node. */
|
|
6
7
|
export function createCommentNode(options: Partial<Lunch.CommentMeta> = {}) {
|
|
@@ -74,9 +75,12 @@ export function createNode<T extends object = THREE.Object3D>(
|
|
|
74
75
|
})
|
|
75
76
|
}
|
|
76
77
|
|
|
77
|
-
|
|
78
|
+
// TODO: these manual overrides are a bit brittle - replace?
|
|
79
|
+
if (node.type?.toLowerCase() === 'scene') {
|
|
78
80
|
// manually set scene override
|
|
79
81
|
ensuredScene.value = node as Lunch.Node<THREE.Scene>
|
|
82
|
+
} else if (node.type?.toLowerCase().endsWith('camera')) {
|
|
83
|
+
ensuredCamera.value = node as Lunch.Node<THREE.Camera>
|
|
80
84
|
}
|
|
81
85
|
|
|
82
86
|
return node
|
package/src/core/ensure.ts
CHANGED
|
@@ -158,18 +158,10 @@ export const ensuredCamera = computed<Lunch.Node<THREE.Camera> | null>({
|
|
|
158
158
|
},
|
|
159
159
|
})
|
|
160
160
|
|
|
161
|
-
// export const ensuredCamera = buildEnsured<THREE.Camera>(
|
|
162
|
-
// ['PerspectiveCamera', 'OrthographicCamera'],
|
|
163
|
-
// fallbackCameraUuid,
|
|
164
|
-
// {
|
|
165
|
-
// args: [45, 0.5625, 1, 1000],
|
|
166
|
-
// }
|
|
167
|
-
// )
|
|
168
|
-
|
|
169
161
|
// ENSURE RENDERER
|
|
170
162
|
// ====================
|
|
171
163
|
export const fallbackRendererUuid = 'FALLBACK_RENDERER'
|
|
172
|
-
export const
|
|
164
|
+
export const ensuredRenderer = buildEnsured(
|
|
173
165
|
// TODO: ensure support for css/svg renderers
|
|
174
166
|
['WebGLRenderer'], //, 'CSS2DRenderer', 'CSS3DRenderer', 'SVGRenderer'],
|
|
175
167
|
fallbackRendererUuid,
|
|
@@ -181,7 +173,9 @@ export const rendererReady = ref(false)
|
|
|
181
173
|
|
|
182
174
|
export const ensureRenderer = computed<Lunch.Node<THREE.WebGLRenderer> | null>({
|
|
183
175
|
get() {
|
|
184
|
-
return (
|
|
176
|
+
return (
|
|
177
|
+
rendererReady.value ? (ensuredRenderer.value as any) : (null as any)
|
|
178
|
+
) as any
|
|
185
179
|
},
|
|
186
180
|
set(val: any) {
|
|
187
181
|
const t = val.type ?? ''
|
package/src/index.ts
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
computed,
|
|
3
|
-
createRenderer,
|
|
4
|
-
Component,
|
|
5
|
-
ref,
|
|
6
|
-
watch,
|
|
7
|
-
WatchStopHandle,
|
|
8
|
-
} from 'vue'
|
|
1
|
+
import { computed, createRenderer, Component, ref, watch } from 'vue'
|
|
9
2
|
import { nodeOps } from './nodeOps'
|
|
10
3
|
import {
|
|
11
4
|
// createdCamera,
|
|
@@ -47,20 +40,13 @@ export const globals = {
|
|
|
47
40
|
export const camera = computed(() => ensuredCamera.value?.instance ?? null)
|
|
48
41
|
/** Run a function using the current camera when it's present. */
|
|
49
42
|
export function useCamera<T extends THREE.Camera = THREE.PerspectiveCamera>(
|
|
50
|
-
callback: (cam: T) => void
|
|
51
|
-
once = true
|
|
43
|
+
callback: (cam: T) => void
|
|
52
44
|
) {
|
|
53
|
-
|
|
54
|
-
destroy = watch(
|
|
45
|
+
return watch(
|
|
55
46
|
camera,
|
|
56
47
|
(newVal) => {
|
|
57
48
|
if (!newVal) return
|
|
58
|
-
|
|
59
|
-
// TODO: better fix than `any`?
|
|
60
|
-
callback(newVal as any)
|
|
61
|
-
if (once) {
|
|
62
|
-
destroy?.()
|
|
63
|
-
}
|
|
49
|
+
callback(newVal as unknown as T)
|
|
64
50
|
},
|
|
65
51
|
{ immediate: true }
|
|
66
52
|
)
|
|
@@ -70,20 +56,13 @@ export function useCamera<T extends THREE.Camera = THREE.PerspectiveCamera>(
|
|
|
70
56
|
export const renderer = computed(() => ensureRenderer.value?.instance ?? null)
|
|
71
57
|
/** Run a function using the current renderer when it's present. */
|
|
72
58
|
export function useRenderer<T extends THREE.Renderer = THREE.WebGLRenderer>(
|
|
73
|
-
callback: (rend: T) => void
|
|
74
|
-
once = true
|
|
59
|
+
callback: (rend: T) => void
|
|
75
60
|
) {
|
|
76
|
-
|
|
77
|
-
destroy = watch(
|
|
61
|
+
return watch(
|
|
78
62
|
renderer,
|
|
79
63
|
(newVal) => {
|
|
80
64
|
if (!newVal) return
|
|
81
|
-
|
|
82
|
-
// TODO: better fix than `any`?
|
|
83
|
-
callback(newVal as any)
|
|
84
|
-
if (once) {
|
|
85
|
-
destroy?.()
|
|
86
|
-
}
|
|
65
|
+
callback(newVal as unknown as T)
|
|
87
66
|
},
|
|
88
67
|
{ immediate: true }
|
|
89
68
|
)
|
|
@@ -92,21 +71,12 @@ export function useRenderer<T extends THREE.Renderer = THREE.WebGLRenderer>(
|
|
|
92
71
|
/** The current scene. Often easier to use `useScene` instead of this. */
|
|
93
72
|
export const scene = computed(() => ensuredScene.value.instance)
|
|
94
73
|
/** Run a function using the current scene when it's present. */
|
|
95
|
-
export function useScene(
|
|
96
|
-
|
|
97
|
-
once = true
|
|
98
|
-
) {
|
|
99
|
-
let destroy: WatchStopHandle
|
|
100
|
-
destroy = watch(
|
|
74
|
+
export function useScene(callback: (newScene: THREE.Scene) => void) {
|
|
75
|
+
return watch(
|
|
101
76
|
scene,
|
|
102
77
|
(newVal) => {
|
|
103
78
|
if (!newVal) return
|
|
104
|
-
|
|
105
|
-
// TODO: better fix than `any`?
|
|
106
79
|
callback(newVal as any)
|
|
107
|
-
if (once) {
|
|
108
|
-
destroy?.()
|
|
109
|
-
}
|
|
110
80
|
},
|
|
111
81
|
{ immediate: true }
|
|
112
82
|
)
|
|
@@ -142,15 +112,17 @@ export const createApp = (root: Component) => {
|
|
|
142
112
|
|
|
143
113
|
// register all components
|
|
144
114
|
Object.keys(components).forEach((key) => {
|
|
145
|
-
app
|
|
115
|
+
app?.component(key, (components as any)[key])
|
|
146
116
|
})
|
|
147
117
|
|
|
148
118
|
// update mount function to match Lunchbox.Node
|
|
149
119
|
const { mount } = app
|
|
150
120
|
app.mount = (root, ...args) => {
|
|
121
|
+
// find DOM element to use as app root
|
|
151
122
|
const domElement = (
|
|
152
123
|
typeof root === 'string' ? document.querySelector(root) : root
|
|
153
124
|
) as HTMLElement
|
|
125
|
+
// create or find root node
|
|
154
126
|
const rootNode = ensureRootNode({
|
|
155
127
|
domElement,
|
|
156
128
|
isLunchboxRootNode: true,
|
package/src/nodeOps/remove.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -145,6 +145,7 @@ export declare namespace Lunch {
|
|
|
145
145
|
dpr?: number
|
|
146
146
|
ortho?: boolean
|
|
147
147
|
orthographic?: boolean
|
|
148
|
+
r3f?: boolean
|
|
148
149
|
// TODO: Why doesn't ConstructorParameters<THREE.WebGLRenderer> work here?
|
|
149
150
|
rendererArguments?: object
|
|
150
151
|
rendererProperties?: Partial<THREE.WebGLRenderer>
|