lunchboxjs 0.1.4013 → 0.1.4016
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/README.md +14 -0
- package/dist/.DS_Store +0 -0
- package/dist/lunchboxjs.js +152 -110
- package/dist/lunchboxjs.min.js +1 -1
- package/dist/lunchboxjs.module.js +152 -111
- package/package.json +10 -5
- package/src/.DS_Store +0 -0
- package/src/components/LunchboxWrapper/LunchboxWrapper.ts +36 -3
- package/src/components/LunchboxWrapper/prepCanvas.ts +2 -2
- package/src/components/catalogue.ts +1 -1
- package/src/core/.DS_Store +0 -0
- package/src/core/createNode.ts +5 -1
- package/src/core/ensure.ts +4 -10
- package/src/core/instantiateThreeObject/processProps.ts +23 -6
- package/src/core/interaction/input.ts +1 -1
- package/src/core/interaction/setupAutoRaycaster.ts +12 -2
- package/src/core/update.ts +29 -3
- package/src/index.ts +12 -40
- package/src/nodeOps/remove.ts +0 -1
- package/src/types.ts +4 -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,11 +91,13 @@ 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],
|
|
96
98
|
transparent: Boolean,
|
|
97
99
|
zoom: Number,
|
|
100
|
+
updateSource: Object,
|
|
98
101
|
},
|
|
99
102
|
setup(props, context) {
|
|
100
103
|
const canvas = ref();
|
|
@@ -104,6 +107,10 @@ const LunchboxWrapper = {
|
|
|
104
107
|
let renderer;
|
|
105
108
|
let camera;
|
|
106
109
|
let scene;
|
|
110
|
+
// https://threejs.org/docs/index.html#manual/en/introduction/Color-management
|
|
111
|
+
if (props.r3f && THREE?.ColorManagement) {
|
|
112
|
+
THREE.ColorManagement.legacyMode = false;
|
|
113
|
+
}
|
|
107
114
|
// MOUNT
|
|
108
115
|
// ====================
|
|
109
116
|
onMounted(() => {
|
|
@@ -124,6 +131,9 @@ const LunchboxWrapper = {
|
|
|
124
131
|
alpha: props.transparent,
|
|
125
132
|
antialias: true,
|
|
126
133
|
canvas: canvas.value.domElement,
|
|
134
|
+
powerPreference: !!props.r3f
|
|
135
|
+
? 'high-performance'
|
|
136
|
+
: 'default',
|
|
127
137
|
...(props.rendererArguments ?? {}),
|
|
128
138
|
};
|
|
129
139
|
// create new renderer
|
|
@@ -137,6 +147,15 @@ const LunchboxWrapper = {
|
|
|
137
147
|
// we've initialized the renderer, so anything depending on it can execute now
|
|
138
148
|
rendererReady.value = true;
|
|
139
149
|
const rendererAsWebGlRenderer = ensureRenderer;
|
|
150
|
+
// apply r3f settings if desired
|
|
151
|
+
if (props.r3f) {
|
|
152
|
+
if (rendererAsWebGlRenderer.value.instance) {
|
|
153
|
+
rendererAsWebGlRenderer.value.instance.outputEncoding =
|
|
154
|
+
THREE.sRGBEncoding;
|
|
155
|
+
rendererAsWebGlRenderer.value.instance.toneMapping =
|
|
156
|
+
THREE.ACESFilmicToneMapping;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
140
159
|
// update render sugar
|
|
141
160
|
const sugar = {
|
|
142
161
|
shadow: props.shadow,
|
|
@@ -184,7 +203,12 @@ const LunchboxWrapper = {
|
|
|
184
203
|
else {
|
|
185
204
|
ensuredCamera.value = createNode({
|
|
186
205
|
props: {
|
|
187
|
-
args: props.cameraArgs ?? [
|
|
206
|
+
args: props.cameraArgs ?? [
|
|
207
|
+
props.r3f ? 75 : 45,
|
|
208
|
+
0.5625,
|
|
209
|
+
1,
|
|
210
|
+
1000,
|
|
211
|
+
],
|
|
188
212
|
},
|
|
189
213
|
type: 'PerspectiveCamera',
|
|
190
214
|
uuid: fallbackCameraUuid,
|
|
@@ -217,7 +241,7 @@ const LunchboxWrapper = {
|
|
|
217
241
|
scene = ensuredScene.value;
|
|
218
242
|
// set background color
|
|
219
243
|
if (scene && scene.instance && props.background) {
|
|
220
|
-
scene.instance.background = new Color(props.background);
|
|
244
|
+
scene.instance.background = new THREE.Color(props.background);
|
|
221
245
|
}
|
|
222
246
|
// MISC PROPERTIES
|
|
223
247
|
// ====================
|
|
@@ -253,12 +277,14 @@ const LunchboxWrapper = {
|
|
|
253
277
|
camera: camera.instance,
|
|
254
278
|
renderer: renderer.instance,
|
|
255
279
|
scene: scene.instance,
|
|
280
|
+
updateSource: props.updateSource,
|
|
256
281
|
});
|
|
257
282
|
});
|
|
258
283
|
// UNMOUNT
|
|
259
284
|
// ====================
|
|
260
285
|
onBeforeUnmount(() => {
|
|
261
286
|
cancelUpdate();
|
|
287
|
+
cancelUpdateSource();
|
|
262
288
|
});
|
|
263
289
|
// RENDER FUNCTION
|
|
264
290
|
// ====================
|
|
@@ -523,76 +549,6 @@ const isLunchboxRootNode = (node) => {
|
|
|
523
549
|
return node.isLunchboxRootNode;
|
|
524
550
|
};
|
|
525
551
|
|
|
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
552
|
const interactables = [];
|
|
597
553
|
const addInteractable = (target) => {
|
|
598
554
|
interactables.push(target);
|
|
@@ -674,6 +630,7 @@ let mouseDownListener;
|
|
|
674
630
|
let mouseUpListener;
|
|
675
631
|
const mousePos = ref({ x: Infinity, y: Infinity });
|
|
676
632
|
let autoRaycasterEventsInitialized = false;
|
|
633
|
+
let frameID$1;
|
|
677
634
|
const setupAutoRaycaster = (node) => {
|
|
678
635
|
const instance = node.instance;
|
|
679
636
|
if (!instance)
|
|
@@ -706,8 +663,14 @@ const setupAutoRaycaster = (node) => {
|
|
|
706
663
|
renderer.instance.domElement.addEventListener('mousedown', mouseDownListener);
|
|
707
664
|
renderer.instance.domElement.addEventListener('mouseup', mouseUpListener);
|
|
708
665
|
// TODO: add touch events
|
|
709
|
-
//
|
|
710
|
-
|
|
666
|
+
// process mouse events asynchronously, whenever the mouse state changes
|
|
667
|
+
watch(() => [inputActive.value, mousePos.value.x, mousePos.value.y], () => {
|
|
668
|
+
if (frameID$1)
|
|
669
|
+
cancelAnimationFrame(frameID$1);
|
|
670
|
+
frameID$1 = requestAnimationFrame(() => {
|
|
671
|
+
autoRaycasterBeforeRender();
|
|
672
|
+
});
|
|
673
|
+
});
|
|
711
674
|
// mark complete
|
|
712
675
|
autoRaycasterEventsInitialized = true;
|
|
713
676
|
// cancel setup watcher
|
|
@@ -918,17 +881,10 @@ const ensuredCamera = computed({
|
|
|
918
881
|
overrides[pascalType] = val;
|
|
919
882
|
},
|
|
920
883
|
});
|
|
921
|
-
// export const ensuredCamera = buildEnsured<THREE.Camera>(
|
|
922
|
-
// ['PerspectiveCamera', 'OrthographicCamera'],
|
|
923
|
-
// fallbackCameraUuid,
|
|
924
|
-
// {
|
|
925
|
-
// args: [45, 0.5625, 1, 1000],
|
|
926
|
-
// }
|
|
927
|
-
// )
|
|
928
884
|
// ENSURE RENDERER
|
|
929
885
|
// ====================
|
|
930
886
|
const fallbackRendererUuid = 'FALLBACK_RENDERER';
|
|
931
|
-
const
|
|
887
|
+
const ensuredRenderer = buildEnsured(
|
|
932
888
|
// TODO: ensure support for css/svg renderers
|
|
933
889
|
['WebGLRenderer'], //, 'CSS2DRenderer', 'CSS3DRenderer', 'SVGRenderer'],
|
|
934
890
|
fallbackRendererUuid, {});
|
|
@@ -937,7 +893,7 @@ fallbackRendererUuid, {});
|
|
|
937
893
|
const rendererReady = ref(false);
|
|
938
894
|
const ensureRenderer = computed({
|
|
939
895
|
get() {
|
|
940
|
-
return (rendererReady.value ?
|
|
896
|
+
return (rendererReady.value ? ensuredRenderer.value : null);
|
|
941
897
|
},
|
|
942
898
|
set(val) {
|
|
943
899
|
const t = val.type ?? '';
|
|
@@ -954,6 +910,80 @@ const autoRaycasterUuid = 'AUTO_RAYCASTER';
|
|
|
954
910
|
// `unknown` is intentional here - we need to typecast the node since Raycaster isn't an Object3D
|
|
955
911
|
const ensuredRaycaster = buildEnsured('Raycaster', autoRaycasterUuid, {}, (node) => setupAutoRaycaster(node));
|
|
956
912
|
|
|
913
|
+
/** Create a new Lunchbox comment node. */
|
|
914
|
+
function createCommentNode(options = {}) {
|
|
915
|
+
const defaults = {
|
|
916
|
+
text: options.text ?? '',
|
|
917
|
+
};
|
|
918
|
+
return new MiniDom.RendererCommentNode({
|
|
919
|
+
...defaults,
|
|
920
|
+
...options,
|
|
921
|
+
metaType: 'commentMeta',
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
/** Create a new DOM node. */
|
|
925
|
+
function createDomNode(options = {}) {
|
|
926
|
+
const domElement = document.createElement(options.type ?? '');
|
|
927
|
+
const defaults = {
|
|
928
|
+
domElement,
|
|
929
|
+
};
|
|
930
|
+
const node = new MiniDom.RendererDomNode({
|
|
931
|
+
...defaults,
|
|
932
|
+
...options,
|
|
933
|
+
metaType: 'domMeta',
|
|
934
|
+
});
|
|
935
|
+
return node;
|
|
936
|
+
}
|
|
937
|
+
/** Create a new Lunchbox text node. */
|
|
938
|
+
function createTextNode(options = {}) {
|
|
939
|
+
const defaults = {
|
|
940
|
+
text: options.text ?? '',
|
|
941
|
+
};
|
|
942
|
+
return new MiniDom.RendererTextNode({
|
|
943
|
+
...options,
|
|
944
|
+
...defaults,
|
|
945
|
+
metaType: 'textMeta',
|
|
946
|
+
});
|
|
947
|
+
}
|
|
948
|
+
/** Create a new Lunchbox standard node. */
|
|
949
|
+
function createNode(options = {}, props = {}) {
|
|
950
|
+
const defaults = {
|
|
951
|
+
attached: options.attached ?? [],
|
|
952
|
+
attachedArray: options.attachedArray ?? {},
|
|
953
|
+
instance: options.instance ?? null,
|
|
954
|
+
};
|
|
955
|
+
const node = new MiniDom.RendererStandardNode({
|
|
956
|
+
...options,
|
|
957
|
+
...defaults,
|
|
958
|
+
metaType: 'standardMeta',
|
|
959
|
+
});
|
|
960
|
+
if (node.type && !isLunchboxRootNode(node) && !node.instance) {
|
|
961
|
+
// if (node.type.includes('Camera')) {
|
|
962
|
+
// console.log(node.type, {
|
|
963
|
+
// ...node.props,
|
|
964
|
+
// ...props,
|
|
965
|
+
// })
|
|
966
|
+
// console.trace()
|
|
967
|
+
// }
|
|
968
|
+
node.instance = instantiateThreeObject({
|
|
969
|
+
...node,
|
|
970
|
+
props: {
|
|
971
|
+
...node.props,
|
|
972
|
+
...props,
|
|
973
|
+
},
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
// TODO: these manual overrides are a bit brittle - replace?
|
|
977
|
+
if (node.type?.toLowerCase() === 'scene') {
|
|
978
|
+
// manually set scene override
|
|
979
|
+
ensuredScene.value = node;
|
|
980
|
+
}
|
|
981
|
+
else if (node.type?.toLowerCase().endsWith('camera')) {
|
|
982
|
+
ensuredCamera.value = node;
|
|
983
|
+
}
|
|
984
|
+
return node;
|
|
985
|
+
}
|
|
986
|
+
|
|
957
987
|
const createComponent = (tag) => defineComponent({
|
|
958
988
|
inheritAttrs: false,
|
|
959
989
|
name: tag,
|
|
@@ -969,7 +999,7 @@ const extend = ({ app, ...targets }) => {
|
|
|
969
999
|
};
|
|
970
1000
|
|
|
971
1001
|
/** Process props into either themselves or the $attached value */
|
|
972
|
-
function processProp({ node, prop }) {
|
|
1002
|
+
function processProp({ node, prop, }) {
|
|
973
1003
|
// return $attachedArray value if needed
|
|
974
1004
|
if (typeof prop === 'string' && prop.startsWith('$attachedArray')) {
|
|
975
1005
|
return node.attachedArray[prop.replace('$attachedArray.', '')];
|
|
@@ -981,10 +1011,12 @@ function processProp({ node, prop }) {
|
|
|
981
1011
|
// otherwise, return plain value
|
|
982
1012
|
return prop;
|
|
983
1013
|
}
|
|
984
|
-
function processPropAsArray({ node, prop }) {
|
|
1014
|
+
function processPropAsArray({ node, prop, }) {
|
|
985
1015
|
const isAttachedArray = typeof prop === 'string' && prop.startsWith('$attachedArray');
|
|
986
1016
|
const output = processProp({ node, prop });
|
|
987
|
-
return Array.isArray(output) && isAttachedArray
|
|
1017
|
+
return Array.isArray(output) && isAttachedArray
|
|
1018
|
+
? output
|
|
1019
|
+
: [output];
|
|
988
1020
|
}
|
|
989
1021
|
|
|
990
1022
|
function instantiateThreeObject(node) {
|
|
@@ -1283,16 +1315,34 @@ const onStart = (cb, index = Infinity) => {
|
|
|
1283
1315
|
};
|
|
1284
1316
|
|
|
1285
1317
|
let frameID;
|
|
1318
|
+
let watchStopHandle;
|
|
1286
1319
|
const beforeRender = [];
|
|
1287
1320
|
const afterRender = [];
|
|
1288
|
-
const
|
|
1289
|
-
|
|
1321
|
+
const requestUpdate = (opts) => {
|
|
1322
|
+
cancelUpdate();
|
|
1290
1323
|
frameID = requestAnimationFrame(() => update({
|
|
1291
1324
|
app: opts.app,
|
|
1292
1325
|
renderer: ensureRenderer.value?.instance,
|
|
1293
1326
|
scene: ensuredScene.value.instance,
|
|
1294
1327
|
camera: ensuredCamera.value?.instance,
|
|
1328
|
+
updateSource: opts.updateSource,
|
|
1295
1329
|
}));
|
|
1330
|
+
};
|
|
1331
|
+
const update = (opts) => {
|
|
1332
|
+
if (opts.updateSource) {
|
|
1333
|
+
if (!watchStopHandle) {
|
|
1334
|
+
// request next frame only when state changes
|
|
1335
|
+
watchStopHandle = watch(opts.updateSource, () => {
|
|
1336
|
+
requestUpdate(opts);
|
|
1337
|
+
}, {
|
|
1338
|
+
deep: true,
|
|
1339
|
+
});
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
else {
|
|
1343
|
+
// request next frame on a continuous loop
|
|
1344
|
+
requestUpdate(opts);
|
|
1345
|
+
}
|
|
1296
1346
|
// prep options
|
|
1297
1347
|
const { app, renderer, scene, camera } = opts;
|
|
1298
1348
|
// BEFORE RENDER
|
|
@@ -1355,6 +1405,10 @@ const cancelUpdate = () => {
|
|
|
1355
1405
|
if (frameID)
|
|
1356
1406
|
cancelAnimationFrame(frameID);
|
|
1357
1407
|
};
|
|
1408
|
+
const cancelUpdateSource = () => {
|
|
1409
|
+
if (watchStopHandle)
|
|
1410
|
+
watchStopHandle();
|
|
1411
|
+
};
|
|
1358
1412
|
|
|
1359
1413
|
/** Update a single prop on a given node. */
|
|
1360
1414
|
function updateObjectProp({ node, key, value, }) {
|
|
@@ -1710,46 +1764,31 @@ const globals = {
|
|
|
1710
1764
|
/** The current camera. Often easier to use `useCamera` instead of this. */
|
|
1711
1765
|
const camera = computed(() => ensuredCamera.value?.instance ?? null);
|
|
1712
1766
|
/** Run a function using the current camera when it's present. */
|
|
1713
|
-
function useCamera(callback
|
|
1714
|
-
|
|
1715
|
-
destroy = watch(camera, (newVal) => {
|
|
1767
|
+
function useCamera(callback) {
|
|
1768
|
+
return watch(camera, (newVal) => {
|
|
1716
1769
|
if (!newVal)
|
|
1717
1770
|
return;
|
|
1718
|
-
// TODO: better fix than `any`?
|
|
1719
1771
|
callback(newVal);
|
|
1720
|
-
if (once) {
|
|
1721
|
-
destroy?.();
|
|
1722
|
-
}
|
|
1723
1772
|
}, { immediate: true });
|
|
1724
1773
|
}
|
|
1725
1774
|
/** The current renderer. Often easier to use `useRenderer` instead of this. */
|
|
1726
1775
|
const renderer = computed(() => ensureRenderer.value?.instance ?? null);
|
|
1727
1776
|
/** Run a function using the current renderer when it's present. */
|
|
1728
|
-
function useRenderer(callback
|
|
1729
|
-
|
|
1730
|
-
destroy = watch(renderer, (newVal) => {
|
|
1777
|
+
function useRenderer(callback) {
|
|
1778
|
+
return watch(renderer, (newVal) => {
|
|
1731
1779
|
if (!newVal)
|
|
1732
1780
|
return;
|
|
1733
|
-
// TODO: better fix than `any`?
|
|
1734
1781
|
callback(newVal);
|
|
1735
|
-
if (once) {
|
|
1736
|
-
destroy?.();
|
|
1737
|
-
}
|
|
1738
1782
|
}, { immediate: true });
|
|
1739
1783
|
}
|
|
1740
1784
|
/** The current scene. Often easier to use `useScene` instead of this. */
|
|
1741
1785
|
const scene = computed(() => ensuredScene.value.instance);
|
|
1742
1786
|
/** Run a function using the current scene when it's present. */
|
|
1743
|
-
function useScene(callback
|
|
1744
|
-
|
|
1745
|
-
destroy = watch(scene, (newVal) => {
|
|
1787
|
+
function useScene(callback) {
|
|
1788
|
+
return watch(scene, (newVal) => {
|
|
1746
1789
|
if (!newVal)
|
|
1747
1790
|
return;
|
|
1748
|
-
// TODO: better fix than `any`?
|
|
1749
1791
|
callback(newVal);
|
|
1750
|
-
if (once) {
|
|
1751
|
-
destroy?.();
|
|
1752
|
-
}
|
|
1753
1792
|
}, { immediate: true });
|
|
1754
1793
|
}
|
|
1755
1794
|
// CUSTOM RENDER SUPPORT
|
|
@@ -1778,12 +1817,14 @@ const createApp = (root) => {
|
|
|
1778
1817
|
app = createRenderer(nodeOps).createApp(root);
|
|
1779
1818
|
// register all components
|
|
1780
1819
|
Object.keys(components).forEach((key) => {
|
|
1781
|
-
app
|
|
1820
|
+
app?.component(key, components[key]);
|
|
1782
1821
|
});
|
|
1783
1822
|
// update mount function to match Lunchbox.Node
|
|
1784
1823
|
const { mount } = app;
|
|
1785
1824
|
app.mount = (root, ...args) => {
|
|
1825
|
+
// find DOM element to use as app root
|
|
1786
1826
|
const domElement = (typeof root === 'string' ? document.querySelector(root) : root);
|
|
1827
|
+
// create or find root node
|
|
1787
1828
|
const rootNode = ensureRootNode({
|
|
1788
1829
|
domElement,
|
|
1789
1830
|
isLunchboxRootNode: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lunchboxjs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4016",
|
|
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",
|
package/src/.DS_Store
ADDED
|
Binary file
|
|
@@ -5,11 +5,13 @@ import {
|
|
|
5
5
|
onBeforeUnmount,
|
|
6
6
|
onMounted,
|
|
7
7
|
ref,
|
|
8
|
+
WatchSource,
|
|
8
9
|
WritableComputedRef,
|
|
9
10
|
} from 'vue'
|
|
10
11
|
import {
|
|
11
12
|
cameraReady,
|
|
12
13
|
cancelUpdate,
|
|
14
|
+
cancelUpdateSource,
|
|
13
15
|
createNode,
|
|
14
16
|
ensuredCamera,
|
|
15
17
|
ensureRenderer,
|
|
@@ -24,9 +26,13 @@ import {
|
|
|
24
26
|
} from '../../core'
|
|
25
27
|
import { set } from 'lodash'
|
|
26
28
|
import { globals, Lunch } from '../..'
|
|
27
|
-
import { Color, Vector2 } from 'three'
|
|
29
|
+
// import { Color, Vector2, sRGBEncoding, ACESFilmicToneMapping } from 'three'
|
|
30
|
+
import * as THREE from 'three'
|
|
28
31
|
import { prepCanvas } from './prepCanvas'
|
|
29
32
|
|
|
33
|
+
// TODO:
|
|
34
|
+
// Continue r3f prop - what else (besides camera fov) makes r3f look good?
|
|
35
|
+
|
|
30
36
|
/** fixed & fill styling for container */
|
|
31
37
|
const fillStyle = (position: string) => {
|
|
32
38
|
return {
|
|
@@ -52,11 +58,13 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
52
58
|
dpr: Number,
|
|
53
59
|
ortho: Boolean,
|
|
54
60
|
orthographic: Boolean,
|
|
61
|
+
r3f: Boolean,
|
|
55
62
|
rendererArguments: Object,
|
|
56
63
|
rendererProperties: Object,
|
|
57
64
|
shadow: [Boolean, Object],
|
|
58
65
|
transparent: Boolean,
|
|
59
66
|
zoom: Number,
|
|
67
|
+
updateSource: Object,
|
|
60
68
|
},
|
|
61
69
|
setup(props: Lunch.WrapperProps, context) {
|
|
62
70
|
const canvas = ref<MiniDom.RendererDomNode>()
|
|
@@ -67,6 +75,11 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
67
75
|
let camera: Lunch.Node<THREE.Camera> | null
|
|
68
76
|
let scene: MiniDom.RendererStandardNode<THREE.Scene>
|
|
69
77
|
|
|
78
|
+
// https://threejs.org/docs/index.html#manual/en/introduction/Color-management
|
|
79
|
+
if (props.r3f && (THREE as any)?.ColorManagement) {
|
|
80
|
+
;(THREE as any).ColorManagement.legacyMode = false
|
|
81
|
+
}
|
|
82
|
+
|
|
70
83
|
// MOUNT
|
|
71
84
|
// ====================
|
|
72
85
|
onMounted(() => {
|
|
@@ -88,6 +101,9 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
88
101
|
alpha: props.transparent,
|
|
89
102
|
antialias: true,
|
|
90
103
|
canvas: canvas.value.domElement,
|
|
104
|
+
powerPreference: !!props.r3f
|
|
105
|
+
? 'high-performance'
|
|
106
|
+
: 'default',
|
|
91
107
|
...(props.rendererArguments ?? {}),
|
|
92
108
|
}
|
|
93
109
|
|
|
@@ -108,6 +124,16 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
108
124
|
Lunch.Node<THREE.WebGLRenderer>
|
|
109
125
|
>
|
|
110
126
|
|
|
127
|
+
// apply r3f settings if desired
|
|
128
|
+
if (props.r3f) {
|
|
129
|
+
if (rendererAsWebGlRenderer.value.instance) {
|
|
130
|
+
rendererAsWebGlRenderer.value.instance.outputEncoding =
|
|
131
|
+
THREE.sRGBEncoding
|
|
132
|
+
rendererAsWebGlRenderer.value.instance.toneMapping =
|
|
133
|
+
THREE.ACESFilmicToneMapping
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
111
137
|
// update render sugar
|
|
112
138
|
const sugar = {
|
|
113
139
|
shadow: props.shadow,
|
|
@@ -160,7 +186,12 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
160
186
|
} else {
|
|
161
187
|
ensuredCamera.value = createNode<THREE.PerspectiveCamera>({
|
|
162
188
|
props: {
|
|
163
|
-
args: props.cameraArgs ?? [
|
|
189
|
+
args: props.cameraArgs ?? [
|
|
190
|
+
props.r3f ? 75 : 45,
|
|
191
|
+
0.5625,
|
|
192
|
+
1,
|
|
193
|
+
1000,
|
|
194
|
+
],
|
|
164
195
|
},
|
|
165
196
|
type: 'PerspectiveCamera',
|
|
166
197
|
uuid: fallbackCameraUuid,
|
|
@@ -195,7 +226,7 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
195
226
|
scene = ensuredScene.value
|
|
196
227
|
// set background color
|
|
197
228
|
if (scene && scene.instance && props.background) {
|
|
198
|
-
scene.instance.background = new Color(props.background)
|
|
229
|
+
scene.instance.background = new THREE.Color(props.background)
|
|
199
230
|
}
|
|
200
231
|
|
|
201
232
|
// MISC PROPERTIES
|
|
@@ -239,6 +270,7 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
239
270
|
camera: camera.instance,
|
|
240
271
|
renderer: renderer.instance,
|
|
241
272
|
scene: scene.instance,
|
|
273
|
+
updateSource: props.updateSource,
|
|
242
274
|
})
|
|
243
275
|
})
|
|
244
276
|
|
|
@@ -246,6 +278,7 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
246
278
|
// ====================
|
|
247
279
|
onBeforeUnmount(() => {
|
|
248
280
|
cancelUpdate()
|
|
281
|
+
cancelUpdateSource()
|
|
249
282
|
})
|
|
250
283
|
|
|
251
284
|
// RENDER FUNCTION
|
|
@@ -5,7 +5,7 @@ import { resizeCanvas } from './resizeCanvas'
|
|
|
5
5
|
export const prepCanvas = (
|
|
6
6
|
container: Ref<MiniDom.RendererDomNode | undefined>,
|
|
7
7
|
canvasElement: HTMLCanvasElement,
|
|
8
|
-
onBeforeUnmount: Function
|
|
8
|
+
onBeforeUnmount: Function
|
|
9
9
|
) => {
|
|
10
10
|
const containerElement = container.value?.domElement
|
|
11
11
|
if (!containerElement) throw new Error('missing container')
|
|
@@ -29,4 +29,4 @@ export const prepCanvas = (
|
|
|
29
29
|
observer.unobserve(canvasElement)
|
|
30
30
|
}
|
|
31
31
|
})
|
|
32
|
-
}
|
|
32
|
+
}
|
|
Binary file
|
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
|