lunchboxjs 0.1.4001 → 0.1.4005
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 +3 -0
- package/dist/lunchboxjs.js +407 -226
- package/dist/lunchboxjs.min.js +1 -1
- package/dist/lunchboxjs.module.js +405 -227
- package/extras/Gltf.vue +2 -2
- package/extras/OrbitControlsWrapper.vue +9 -10
- package/package.json +24 -3
- package/src/components/LunchboxWrapper/LunchboxWrapper.ts +125 -33
- package/src/components/LunchboxWrapper/resizeCanvas.ts +17 -7
- package/src/components/autoGeneratedComponents.ts +175 -0
- package/src/components/index.ts +5 -188
- package/src/core/createNode.ts +19 -9
- package/src/core/ensure.ts +166 -130
- package/src/core/instantiateThreeObject/index.ts +6 -4
- package/src/core/interaction/index.ts +4 -2
- package/src/core/interaction/setupAutoRaycaster.ts +6 -6
- package/src/core/minidom.ts +85 -27
- package/src/core/update.ts +36 -26
- package/src/index.ts +62 -22
- package/src/nodeOps/createElement.ts +3 -6
- package/src/nodeOps/insert.ts +6 -4
- package/src/nodeOps/remove.ts +19 -5
- package/src/types.ts +10 -0
package/src/components/index.ts
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
import { h, defineComponent } from 'vue'
|
|
2
|
-
// import Gltf from './Gltf'
|
|
3
|
-
// import { Lunchbox } from '../types'
|
|
4
2
|
import { LunchboxWrapper } from './LunchboxWrapper/LunchboxWrapper'
|
|
3
|
+
import { autoGeneratedComponents } from './autoGeneratedComponents'
|
|
5
4
|
|
|
6
5
|
import { catalogue } from './catalogue'
|
|
7
6
|
export { catalogue }
|
|
8
7
|
|
|
9
|
-
export const lunchboxDomComponentNames = [
|
|
10
|
-
'canvas',
|
|
11
|
-
'div',
|
|
12
|
-
'LunchboxWrapper',
|
|
13
|
-
]
|
|
8
|
+
export const lunchboxDomComponentNames = ['canvas', 'div', 'LunchboxWrapper']
|
|
14
9
|
|
|
15
10
|
// component creation utility
|
|
16
11
|
const createComponent = (tag: string) =>
|
|
@@ -22,190 +17,12 @@ const createComponent = (tag: string) =>
|
|
|
22
17
|
},
|
|
23
18
|
})
|
|
24
19
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
// ThreeJS basics
|
|
29
|
-
'mesh',
|
|
30
|
-
'instancedMesh',
|
|
31
|
-
'scene',
|
|
32
|
-
'sprite',
|
|
33
|
-
'object3D',
|
|
34
|
-
|
|
35
|
-
// geometry
|
|
36
|
-
'instancedBufferGeometry',
|
|
37
|
-
'bufferGeometry',
|
|
38
|
-
'boxBufferGeometry',
|
|
39
|
-
'circleBufferGeometry',
|
|
40
|
-
'coneBufferGeometry',
|
|
41
|
-
'cylinderBufferGeometry',
|
|
42
|
-
'dodecahedronBufferGeometry',
|
|
43
|
-
'extrudeBufferGeometry',
|
|
44
|
-
'icosahedronBufferGeometry',
|
|
45
|
-
'latheBufferGeometry',
|
|
46
|
-
'octahedronBufferGeometry',
|
|
47
|
-
'parametricBufferGeometry',
|
|
48
|
-
'planeBufferGeometry',
|
|
49
|
-
'polyhedronBufferGeometry',
|
|
50
|
-
'ringBufferGeometry',
|
|
51
|
-
'shapeBufferGeometry',
|
|
52
|
-
'sphereBufferGeometry',
|
|
53
|
-
'tetrahedronBufferGeometry',
|
|
54
|
-
'textBufferGeometry',
|
|
55
|
-
'torusBufferGeometry',
|
|
56
|
-
'torusKnotBufferGeometry',
|
|
57
|
-
'tubeBufferGeometry',
|
|
58
|
-
'wireframeGeometry',
|
|
59
|
-
'parametricGeometry',
|
|
60
|
-
'tetrahedronGeometry',
|
|
61
|
-
'octahedronGeometry',
|
|
62
|
-
'icosahedronGeometry',
|
|
63
|
-
'dodecahedronGeometry',
|
|
64
|
-
'polyhedronGeometry',
|
|
65
|
-
'tubeGeometry',
|
|
66
|
-
'torusKnotGeometry',
|
|
67
|
-
'torusGeometry',
|
|
68
|
-
// textgeometry has been moved to /examples/jsm/geometries/TextGeometry
|
|
69
|
-
// 'textGeometry',
|
|
70
|
-
'sphereGeometry',
|
|
71
|
-
'ringGeometry',
|
|
72
|
-
'planeGeometry',
|
|
73
|
-
'latheGeometry',
|
|
74
|
-
'shapeGeometry',
|
|
75
|
-
'extrudeGeometry',
|
|
76
|
-
'edgesGeometry',
|
|
77
|
-
'coneGeometry',
|
|
78
|
-
'cylinderGeometry',
|
|
79
|
-
'circleGeometry',
|
|
80
|
-
'boxGeometry',
|
|
81
|
-
|
|
82
|
-
// materials
|
|
83
|
-
'material',
|
|
84
|
-
'shadowMaterial',
|
|
85
|
-
'spriteMaterial',
|
|
86
|
-
'rawShaderMaterial',
|
|
87
|
-
'shaderMaterial',
|
|
88
|
-
'pointsMaterial',
|
|
89
|
-
'meshPhysicalMaterial',
|
|
90
|
-
'meshStandardMaterial',
|
|
91
|
-
'meshPhongMaterial',
|
|
92
|
-
'meshToonMaterial',
|
|
93
|
-
'meshNormalMaterial',
|
|
94
|
-
'meshLambertMaterial',
|
|
95
|
-
'meshDepthMaterial',
|
|
96
|
-
'meshDistanceMaterial',
|
|
97
|
-
'meshBasicMaterial',
|
|
98
|
-
'meshMatcapMaterial',
|
|
99
|
-
'lineDashedMaterial',
|
|
100
|
-
'lineBasicMaterial',
|
|
101
|
-
|
|
102
|
-
// lights
|
|
103
|
-
'light',
|
|
104
|
-
'spotLightShadow',
|
|
105
|
-
'spotLight',
|
|
106
|
-
'pointLight',
|
|
107
|
-
'rectAreaLight',
|
|
108
|
-
'hemisphereLight',
|
|
109
|
-
'directionalLightShadow',
|
|
110
|
-
'directionalLight',
|
|
111
|
-
'ambientLight',
|
|
112
|
-
'lightShadow',
|
|
113
|
-
'ambientLightProbe',
|
|
114
|
-
'hemisphereLightProbe',
|
|
115
|
-
'lightProbe',
|
|
116
|
-
|
|
117
|
-
// textures
|
|
118
|
-
'texture',
|
|
119
|
-
'videoTexture',
|
|
120
|
-
'dataTexture',
|
|
121
|
-
'dataTexture3D',
|
|
122
|
-
'compressedTexture',
|
|
123
|
-
'cubeTexture',
|
|
124
|
-
'canvasTexture',
|
|
125
|
-
'depthTexture',
|
|
126
|
-
|
|
127
|
-
// Texture loaders
|
|
128
|
-
'textureLoader',
|
|
129
|
-
|
|
130
|
-
// misc
|
|
131
|
-
'group',
|
|
132
|
-
'catmullRomCurve3',
|
|
133
|
-
'points',
|
|
134
|
-
|
|
135
|
-
// helpers
|
|
136
|
-
'cameraHelper',
|
|
137
|
-
|
|
138
|
-
// cameras
|
|
139
|
-
'camera',
|
|
140
|
-
'perspectiveCamera',
|
|
141
|
-
'orthographicCamera',
|
|
142
|
-
'cubeCamera',
|
|
143
|
-
'arrayCamera',
|
|
144
|
-
|
|
145
|
-
// renderers
|
|
146
|
-
'webGLRenderer',
|
|
147
|
-
].map(createComponent).reduce((acc, curr) => {
|
|
148
|
-
; (acc as any)[curr.name] = curr
|
|
20
|
+
autoGeneratedComponents.map(createComponent).reduce((acc, curr) => {
|
|
21
|
+
;(acc as any)[curr.name] = curr
|
|
149
22
|
return acc
|
|
150
23
|
})
|
|
151
24
|
|
|
152
25
|
export const components = {
|
|
153
26
|
...autoGeneratedComponents,
|
|
154
|
-
|
|
155
|
-
// Gltf,
|
|
27
|
+
Lunchbox: LunchboxWrapper,
|
|
156
28
|
}
|
|
157
|
-
|
|
158
|
-
// console.log(components, Gltf)
|
|
159
|
-
|
|
160
|
-
/*
|
|
161
|
-
// List copied from r3f
|
|
162
|
-
// https://github.com/pmndrs/react-three-fiber/blob/master/packages/fiber/src/three-types.ts
|
|
163
|
-
|
|
164
|
-
// NOT IMPLEMENTED:
|
|
165
|
-
audioListener: AudioListenerProps
|
|
166
|
-
positionalAudio: PositionalAudioProps
|
|
167
|
-
|
|
168
|
-
lOD: LODProps
|
|
169
|
-
skinnedMesh: SkinnedMeshProps
|
|
170
|
-
skeleton: SkeletonProps
|
|
171
|
-
bone: BoneProps
|
|
172
|
-
lineSegments: LineSegmentsProps
|
|
173
|
-
lineLoop: LineLoopProps
|
|
174
|
-
// see `audio`
|
|
175
|
-
// line: LineProps
|
|
176
|
-
immediateRenderObject: ImmediateRenderObjectProps
|
|
177
|
-
|
|
178
|
-
// primitive
|
|
179
|
-
primitive: PrimitiveProps
|
|
180
|
-
|
|
181
|
-
// helpers
|
|
182
|
-
spotLightHelper: SpotLightHelperProps
|
|
183
|
-
skeletonHelper: SkeletonHelperProps
|
|
184
|
-
pointLightHelper: PointLightHelperProps
|
|
185
|
-
hemisphereLightHelper: HemisphereLightHelperProps
|
|
186
|
-
gridHelper: GridHelperProps
|
|
187
|
-
polarGridHelper: PolarGridHelperProps
|
|
188
|
-
directionalLightHelper: DirectionalLightHelperProps
|
|
189
|
-
boxHelper: BoxHelperProps
|
|
190
|
-
box3Helper: Box3HelperProps
|
|
191
|
-
planeHelper: PlaneHelperProps
|
|
192
|
-
arrowHelper: ArrowHelperProps
|
|
193
|
-
axesHelper: AxesHelperProps
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
// misc
|
|
197
|
-
raycaster: RaycasterProps
|
|
198
|
-
vector2: Vector2Props
|
|
199
|
-
vector3: Vector3Props
|
|
200
|
-
vector4: Vector4Props
|
|
201
|
-
euler: EulerProps
|
|
202
|
-
matrix3: Matrix3Props
|
|
203
|
-
matrix4: Matrix4Props
|
|
204
|
-
quaternion: QuaternionProps
|
|
205
|
-
bufferAttribute: BufferAttributeProps
|
|
206
|
-
instancedBufferAttribute: InstancedBufferAttributeProps
|
|
207
|
-
color: ColorProps
|
|
208
|
-
fog: FogProps
|
|
209
|
-
fogExp2: FogExp2Props
|
|
210
|
-
shape: ShapeProps
|
|
211
|
-
*/
|
package/src/core/createNode.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { isLunchboxRootNode } from '../utils'
|
|
2
|
-
import { instantiateThreeObject, MiniDom } from '.'
|
|
2
|
+
import { instantiateThreeObject, MiniDom, ensuredScene } from '.'
|
|
3
3
|
import { Lunch } from '..'
|
|
4
4
|
|
|
5
5
|
/** Create a new Lunchbox comment node. */
|
|
6
6
|
export function createCommentNode(options: Partial<Lunch.CommentMeta> = {}) {
|
|
7
7
|
const defaults: Omit<Lunch.CommentMeta, keyof Lunch.MetaBase> = {
|
|
8
|
-
text: options.text ?? ''
|
|
8
|
+
text: options.text ?? '',
|
|
9
9
|
}
|
|
10
10
|
return new MiniDom.RendererCommentNode({
|
|
11
11
|
...defaults,
|
|
@@ -29,11 +29,10 @@ export function createDomNode(options: Partial<Lunch.DomMeta> = {}) {
|
|
|
29
29
|
return node
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
33
32
|
/** Create a new Lunchbox text node. */
|
|
34
33
|
export function createTextNode(options: Partial<Lunch.TextMeta> = {}) {
|
|
35
34
|
const defaults: Omit<Lunch.CommentMeta, keyof Lunch.MetaBase> = {
|
|
36
|
-
text: options.text ?? ''
|
|
35
|
+
text: options.text ?? '',
|
|
37
36
|
}
|
|
38
37
|
return new MiniDom.RendererTextNode({
|
|
39
38
|
...options,
|
|
@@ -45,13 +44,12 @@ export function createTextNode(options: Partial<Lunch.TextMeta> = {}) {
|
|
|
45
44
|
/** Create a new Lunchbox standard node. */
|
|
46
45
|
export function createNode<T extends object = THREE.Object3D>(
|
|
47
46
|
options: Partial<Lunch.StandardMeta<T>> = {},
|
|
48
|
-
props: Lunch.LunchboxMetaProps = {}
|
|
47
|
+
props: Lunch.LunchboxMetaProps = {}
|
|
49
48
|
) {
|
|
50
|
-
|
|
51
49
|
const defaults: Omit<Lunch.StandardMeta<T>, keyof Lunch.MetaBase> = {
|
|
52
50
|
attached: options.attached ?? [],
|
|
53
51
|
attachedArray: options.attachedArray ?? {},
|
|
54
|
-
instance: options.instance ?? null
|
|
52
|
+
instance: options.instance ?? null,
|
|
55
53
|
}
|
|
56
54
|
const node = new MiniDom.RendererStandardNode<T>({
|
|
57
55
|
...options,
|
|
@@ -60,14 +58,26 @@ export function createNode<T extends object = THREE.Object3D>(
|
|
|
60
58
|
})
|
|
61
59
|
|
|
62
60
|
if (node.type && !isLunchboxRootNode(node) && !node.instance) {
|
|
61
|
+
// if (node.type.includes('Camera')) {
|
|
62
|
+
// console.log(node.type, {
|
|
63
|
+
// ...node.props,
|
|
64
|
+
// ...props,
|
|
65
|
+
// })
|
|
66
|
+
// console.trace()
|
|
67
|
+
// }
|
|
63
68
|
node.instance = instantiateThreeObject({
|
|
64
69
|
...node,
|
|
65
70
|
props: {
|
|
66
71
|
...node.props,
|
|
67
72
|
...props,
|
|
68
|
-
}
|
|
73
|
+
},
|
|
69
74
|
})
|
|
70
75
|
}
|
|
71
76
|
|
|
77
|
+
if (node.type === 'scene') {
|
|
78
|
+
// manually set scene override
|
|
79
|
+
ensuredScene.value = node as Lunch.Node<THREE.Scene>
|
|
80
|
+
}
|
|
81
|
+
|
|
72
82
|
return node
|
|
73
|
-
}
|
|
83
|
+
}
|
package/src/core/ensure.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { allNodes, createNode, MiniDom } from '.'
|
|
2
2
|
import { setupAutoRaycaster } from './interaction/setupAutoRaycaster'
|
|
3
|
-
import { ref } from 'vue'
|
|
3
|
+
import { computed, reactive, ref, WritableComputedRef } from 'vue'
|
|
4
4
|
import { Lunch } from '..'
|
|
5
5
|
|
|
6
6
|
// ENSURE ROOT
|
|
@@ -14,151 +14,187 @@ export function ensureRootNode(options: Partial<Lunch.RootMeta> = {}) {
|
|
|
14
14
|
return lunchboxRootNode
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
export
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const foundCamera = allNodes.find((node) =>
|
|
25
|
-
(node as MiniDom.RendererBaseNode).type
|
|
26
|
-
?.toLowerCase()
|
|
27
|
-
.includes('camera')
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
// if we have one, return
|
|
31
|
-
if (foundCamera) {
|
|
32
|
-
const cameraAsStandardNode =
|
|
33
|
-
foundCamera as MiniDom.RendererStandardNode<THREE.Camera>
|
|
34
|
-
createdCamera.value = cameraAsStandardNode
|
|
35
|
-
return cameraAsStandardNode
|
|
17
|
+
// This is used in `buildEnsured` below and `LunchboxWrapper`
|
|
18
|
+
/** Search the overrides record and the node tree for a node in the given types */
|
|
19
|
+
export function tryGetNodeWithInstanceType<T extends THREE.Object3D>(
|
|
20
|
+
pascalCaseTypes: string | string[]
|
|
21
|
+
) {
|
|
22
|
+
if (!Array.isArray(pascalCaseTypes)) {
|
|
23
|
+
pascalCaseTypes = [pascalCaseTypes]
|
|
36
24
|
}
|
|
37
25
|
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
26
|
+
// default to override if we have one
|
|
27
|
+
for (let singleType of pascalCaseTypes) {
|
|
28
|
+
if (overrides[singleType]) return overrides[singleType] as Lunch.Node<T>
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// look for auto-created node
|
|
32
|
+
for (let singleType of pascalCaseTypes) {
|
|
33
|
+
const found =
|
|
34
|
+
autoCreated[singleType] ||
|
|
35
|
+
allNodes.find(
|
|
36
|
+
(node) =>
|
|
37
|
+
(node as MiniDom.RendererBaseNode).type?.toLowerCase() ===
|
|
38
|
+
singleType.toLowerCase()
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
// if we have one, save and return
|
|
42
|
+
if (found) {
|
|
43
|
+
const createdAsNode = found as MiniDom.RendererStandardNode<T>
|
|
44
|
+
autoCreated[singleType] = createdAsNode
|
|
45
|
+
return createdAsNode
|
|
46
|
+
}
|
|
47
|
+
}
|
|
49
48
|
|
|
50
|
-
|
|
51
|
-
ensureScene().instance?.add(cameraNode.instance!)
|
|
52
|
-
return cameraNode
|
|
49
|
+
return null
|
|
53
50
|
}
|
|
54
51
|
|
|
55
|
-
// ENSURE
|
|
52
|
+
// GENERIC ENSURE FUNCTION
|
|
56
53
|
// ====================
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
54
|
+
// Problem:
|
|
55
|
+
// I want to make sure an object of type Xyz exists in my Lunchbox app.
|
|
56
|
+
// If it doesn't exist, I want to create it and add it to the root node.
|
|
57
|
+
//
|
|
58
|
+
// Solution:
|
|
59
|
+
// export const ensuredXyz = buildEnsured<Xyz>('Xyz', 'FALLBACK_XYZ')
|
|
60
|
+
//
|
|
61
|
+
// Now in other components, you can do both:
|
|
62
|
+
// import { ensuredXyz }
|
|
63
|
+
// ensuredXyz.value (...)
|
|
64
|
+
// and:
|
|
65
|
+
// ensuredXyz.value = ...
|
|
66
|
+
export const autoCreated: Record<string, Lunch.Node | null> = reactive({})
|
|
67
|
+
export const overrides: Record<string, Lunch.Node | null> = reactive({})
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Build a computed ensured value with a getter and setter.
|
|
71
|
+
* @param pascalCaseTypes List of types this can be. Will autocreate first type if array provided.
|
|
72
|
+
* @param fallbackUuid Fallback UUID to use.
|
|
73
|
+
* @param props Props to pass to autocreated element
|
|
74
|
+
* @returns Computed getter/setter for ensured object.
|
|
75
|
+
*/
|
|
76
|
+
function buildEnsured<T extends THREE.Object3D>(
|
|
77
|
+
pascalCaseTypes: string | string[],
|
|
78
|
+
fallbackUuid: string,
|
|
79
|
+
props: Record<string, any> = {},
|
|
80
|
+
callback: ((node: MiniDom.RendererStandardNode<T>) => void) | null = null
|
|
81
|
+
) {
|
|
82
|
+
// make sure we've got an array
|
|
83
|
+
if (!Array.isArray(pascalCaseTypes)) {
|
|
84
|
+
pascalCaseTypes = [pascalCaseTypes]
|
|
79
85
|
}
|
|
80
86
|
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
{ args: fallbackArgs }
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
// shadow sugar
|
|
92
|
-
if (sugar?.shadow) {
|
|
93
|
-
rendererNode.instance!.shadowMap.enabled = true
|
|
94
|
-
if (typeof sugar.shadow === 'object') {
|
|
95
|
-
rendererNode.instance!.shadowMap.type = sugar.shadow.type
|
|
87
|
+
// add type for autoCreated and overrides
|
|
88
|
+
for (let singleType of pascalCaseTypes) {
|
|
89
|
+
if (!autoCreated[singleType]) {
|
|
90
|
+
autoCreated[singleType] = null
|
|
91
|
+
}
|
|
92
|
+
if (!overrides[singleType]) {
|
|
93
|
+
overrides[singleType] = null
|
|
96
94
|
}
|
|
97
95
|
}
|
|
98
96
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
97
|
+
return computed({
|
|
98
|
+
get(): MiniDom.RendererStandardNode<T> {
|
|
99
|
+
// try to get existing type
|
|
100
|
+
const existing = tryGetNodeWithInstanceType<T>(
|
|
101
|
+
pascalCaseTypes as string[]
|
|
102
|
+
)
|
|
103
|
+
if (existing) return existing
|
|
104
|
+
|
|
105
|
+
// otherwise, create a new node
|
|
106
|
+
const root = ensureRootNode()
|
|
107
|
+
const node = createNode<T>({
|
|
108
|
+
type: pascalCaseTypes[0],
|
|
109
|
+
uuid: fallbackUuid,
|
|
110
|
+
props,
|
|
111
|
+
})
|
|
112
|
+
root.addChild(node)
|
|
113
|
+
autoCreated[pascalCaseTypes[0]] = node
|
|
114
|
+
if (callback) {
|
|
115
|
+
callback(node)
|
|
116
|
+
}
|
|
117
|
+
return node
|
|
118
|
+
},
|
|
119
|
+
set(val: MiniDom.RendererStandardNode<T>) {
|
|
120
|
+
const t = val.type ?? ''
|
|
121
|
+
const pascalType = t[0].toUpperCase() + t.slice(1)
|
|
122
|
+
overrides[pascalType] = val
|
|
123
|
+
},
|
|
124
|
+
})
|
|
104
125
|
}
|
|
105
126
|
|
|
127
|
+
// ENSURE CAMERA
|
|
128
|
+
// ====================
|
|
129
|
+
export const fallbackCameraUuid = 'FALLBACK_CAMERA'
|
|
130
|
+
export const defaultCamera = buildEnsured(
|
|
131
|
+
['PerspectiveCamera', 'OrthographicCamera'],
|
|
132
|
+
fallbackCameraUuid,
|
|
133
|
+
{ args: [45, 0.5625, 1, 1000] }
|
|
134
|
+
) as unknown as WritableComputedRef<Lunch.Node<THREE.Camera>>
|
|
135
|
+
/** Special value to be changed ONLY in `LunchboxWrapper`.
|
|
136
|
+
* Functions waiting for a Camera need to wait for this to be true. */
|
|
137
|
+
export const cameraReady = ref(false)
|
|
138
|
+
|
|
139
|
+
export const ensuredCamera = computed<Lunch.Node<THREE.Camera> | null>({
|
|
140
|
+
get() {
|
|
141
|
+
return (
|
|
142
|
+
cameraReady.value ? (defaultCamera.value as any) : (null as any)
|
|
143
|
+
) as any
|
|
144
|
+
},
|
|
145
|
+
set(val: any) {
|
|
146
|
+
const t = val.type ?? ''
|
|
147
|
+
const pascalType = t[0].toUpperCase() + t.slice(1)
|
|
148
|
+
overrides[pascalType] = val as any
|
|
149
|
+
},
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
// export const ensuredCamera = buildEnsured<THREE.Camera>(
|
|
153
|
+
// ['PerspectiveCamera', 'OrthographicCamera'],
|
|
154
|
+
// fallbackCameraUuid,
|
|
155
|
+
// {
|
|
156
|
+
// args: [45, 0.5625, 1, 1000],
|
|
157
|
+
// }
|
|
158
|
+
// )
|
|
159
|
+
|
|
160
|
+
// ENSURE RENDERER
|
|
161
|
+
// ====================
|
|
162
|
+
export const fallbackRendererUuid = 'FALLBACK_RENDERER'
|
|
163
|
+
export const v = buildEnsured(
|
|
164
|
+
// TODO: ensure support for css/svg renderers
|
|
165
|
+
['WebGLRenderer'], //, 'CSS2DRenderer', 'CSS3DRenderer', 'SVGRenderer'],
|
|
166
|
+
fallbackRendererUuid,
|
|
167
|
+
{}
|
|
168
|
+
) as unknown as WritableComputedRef<Lunch.Node<THREE.WebGLRenderer>>
|
|
169
|
+
/** Special value to be changed ONLY in `LunchboxWrapper`.
|
|
170
|
+
* Functions waiting for a Renderer need to wait for this to be true. */
|
|
171
|
+
export const rendererReady = ref(false)
|
|
172
|
+
|
|
173
|
+
export const ensureRenderer = computed<Lunch.Node<THREE.WebGLRenderer> | null>({
|
|
174
|
+
get() {
|
|
175
|
+
return (rendererReady.value ? (v.value as any) : (null as any)) as any
|
|
176
|
+
},
|
|
177
|
+
set(val: any) {
|
|
178
|
+
const t = val.type ?? ''
|
|
179
|
+
const pascalType = t[0].toUpperCase() + t.slice(1)
|
|
180
|
+
overrides[pascalType] = val as any
|
|
181
|
+
},
|
|
182
|
+
})
|
|
183
|
+
|
|
106
184
|
// ENSURE SCENE
|
|
107
185
|
// ====================
|
|
108
186
|
export const fallbackSceneUuid = 'FALLBACK_SCENE'
|
|
109
|
-
export const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
(node) =>
|
|
114
|
-
(node as MiniDom.RendererBaseNode).type?.toLowerCase() === 'scene'
|
|
115
|
-
)
|
|
116
|
-
// if we have one, return
|
|
117
|
-
if (foundScene) {
|
|
118
|
-
const sceneAsLunchboxNode =
|
|
119
|
-
foundScene as MiniDom.RendererStandardNode<THREE.Scene>
|
|
120
|
-
createdScene.value = sceneAsLunchboxNode
|
|
121
|
-
return sceneAsLunchboxNode
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// otherwise, create a new scene
|
|
125
|
-
const root = ensureRootNode()
|
|
126
|
-
const sceneNode = createNode<THREE.Scene>({
|
|
127
|
-
type: 'Scene',
|
|
128
|
-
uuid: fallbackSceneUuid,
|
|
129
|
-
})
|
|
130
|
-
root.addChild(sceneNode)
|
|
131
|
-
createdScene.value = sceneNode
|
|
132
|
-
return sceneNode
|
|
133
|
-
}
|
|
187
|
+
export const ensuredScene = buildEnsured<THREE.Scene>(
|
|
188
|
+
'Scene',
|
|
189
|
+
fallbackSceneUuid
|
|
190
|
+
)
|
|
134
191
|
|
|
135
192
|
// ENSURE AUTO-RAYCASTER
|
|
136
193
|
export const autoRaycasterUuid = 'AUTO_RAYCASTER'
|
|
137
|
-
|
|
138
|
-
export const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
if (found) {
|
|
145
|
-
const foundAsNode = found as Lunch.Node<THREE.Raycaster>
|
|
146
|
-
createdRaycaster.value = foundAsNode
|
|
147
|
-
return foundAsNode
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// otherwise, create raycaster
|
|
151
|
-
const root = ensureRootNode()
|
|
152
|
-
const raycasterNode = createNode<THREE.Raycaster>({
|
|
153
|
-
type: 'Raycaster',
|
|
154
|
-
uuid: autoRaycasterUuid,
|
|
155
|
-
})
|
|
156
|
-
root.addChild(raycasterNode)
|
|
157
|
-
createdRaycaster.value = raycasterNode
|
|
158
|
-
|
|
159
|
-
// finish auto-raycaster setup
|
|
160
|
-
setupAutoRaycaster(raycasterNode)
|
|
161
|
-
|
|
162
|
-
// done with raycaster
|
|
163
|
-
return raycasterNode
|
|
164
|
-
}
|
|
194
|
+
// `unknown` is intentional here - we need to typecast the node since Raycaster isn't an Object3D
|
|
195
|
+
export const ensuredRaycaster = buildEnsured(
|
|
196
|
+
'Raycaster',
|
|
197
|
+
autoRaycasterUuid,
|
|
198
|
+
{},
|
|
199
|
+
(node) => setupAutoRaycaster(node as unknown as Lunch.Node<THREE.Raycaster>)
|
|
200
|
+
) as unknown as WritableComputedRef<Lunch.Node<THREE.Raycaster>>
|
|
@@ -9,7 +9,8 @@ export function instantiateThreeObject<T>(node: Lunch.StandardMeta<T>) {
|
|
|
9
9
|
// what class will we be instantiating?
|
|
10
10
|
const uppercaseType = node.type[0].toUpperCase() + node.type.slice(1)
|
|
11
11
|
const targetClass = catalogue[node.type] || (THREE as any)[uppercaseType]
|
|
12
|
-
if (!targetClass)
|
|
12
|
+
if (!targetClass)
|
|
13
|
+
throw `${uppercaseType} is not part of the THREE namespace! Did you forget to extend? import {extend} from 'lunchbox'; extend({app, YourComponent, ...})`
|
|
13
14
|
|
|
14
15
|
// what args have we been provided?
|
|
15
16
|
const args: Array<any> = node.props.args ?? []
|
|
@@ -17,9 +18,11 @@ export function instantiateThreeObject<T>(node: Lunch.StandardMeta<T>) {
|
|
|
17
18
|
// replace $attached values with their instances
|
|
18
19
|
// we need to guarantee everything comes back as an array so we can spread $attachedArrays,
|
|
19
20
|
// so we'll use processPropAsArray
|
|
20
|
-
const argsWrappedInArrays = args.map((arg: any) => {
|
|
21
|
+
const argsWrappedInArrays = args.map((arg: any) => {
|
|
22
|
+
return processPropAsArray({ node, prop: arg })
|
|
23
|
+
})
|
|
21
24
|
let processedArgs = [] as Array<any>
|
|
22
|
-
argsWrappedInArrays.forEach(arr => {
|
|
25
|
+
argsWrappedInArrays.forEach((arr) => {
|
|
23
26
|
processedArgs = processedArgs.concat(arr)
|
|
24
27
|
})
|
|
25
28
|
|
|
@@ -27,4 +30,3 @@ export function instantiateThreeObject<T>(node: Lunch.StandardMeta<T>) {
|
|
|
27
30
|
|
|
28
31
|
return instance as T
|
|
29
32
|
}
|
|
30
|
-
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
interactables,
|
|
5
5
|
removeInteractable,
|
|
6
6
|
} from './interactables'
|
|
7
|
-
import {
|
|
7
|
+
import { ensuredRaycaster } from '..'
|
|
8
8
|
import { inputActive } from './input'
|
|
9
9
|
import { currentIntersections } from '.'
|
|
10
10
|
import { Lunch } from '../..'
|
|
@@ -36,7 +36,9 @@ export function addEventListener({
|
|
|
36
36
|
|
|
37
37
|
// if we need it, let's get/create the main raycaster
|
|
38
38
|
if (interactionsRequiringRaycaster.includes(key)) {
|
|
39
|
-
|
|
39
|
+
// we're not using `v` here, we're just making sure the raycaster has been created
|
|
40
|
+
// TODO: is this necessary?
|
|
41
|
+
const v = ensuredRaycaster.value
|
|
40
42
|
|
|
41
43
|
if (node.instance && !interactables.includes(node)) {
|
|
42
44
|
addInteractable(node)
|