lunchboxjs 0.1.4018 → 0.2.1001-beta.0

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.
@@ -3,7 +3,6 @@ import {
3
3
  isLunchboxRootNode,
4
4
  isLunchboxStandardNode,
5
5
  } from '../utils'
6
- import { ensureRootNode, ensuredScene } from '../core'
7
6
  import { MiniDom } from '../core/minidom'
8
7
  import { Lunch } from '..'
9
8
 
@@ -12,9 +11,12 @@ export const insert = (
12
11
  parent: MiniDom.RendererBaseNode | null,
13
12
  anchor?: MiniDom.RendererBaseNode | null
14
13
  ) => {
14
+ if (!parent) {
15
+ throw new Error('missing parent')
16
+ }
15
17
  // add to parent tree node if we have one
16
- let effectiveParent = parent ?? ensureRootNode()
17
- effectiveParent.insertBefore(child, anchor)
18
+ // let effectiveParent = parent ?? ensureRootNode()
19
+ parent.insertBefore(child, anchor)
18
20
 
19
21
  // handle comment & text nodes
20
22
  if (child.metaType === 'commentMeta' || child.metaType === 'textMeta') {
@@ -33,54 +35,31 @@ export const insert = (
33
35
  // handle standard nodes
34
36
  if (isLunchboxStandardNode(child)) {
35
37
  // let effectiveParent = parent
36
- let effectiveParentNodeType = effectiveParent.metaType
38
+ let effectiveParentNodeType = parent.metaType
37
39
 
38
40
  if (
39
41
  effectiveParentNodeType === 'textMeta' ||
40
42
  effectiveParentNodeType === 'commentMeta'
41
43
  ) {
42
- const path = effectiveParent.getPath() as MiniDom.RendererBaseNode[]
44
+ const path = parent.getPath() as MiniDom.RendererBaseNode[]
43
45
  for (let i = path.length - 1; i >= 0; i--) {
44
46
  if (
45
47
  path[i].metaType !== 'textMeta' &&
46
48
  path[i].metaType !== 'commentMeta'
47
49
  ) {
48
- effectiveParent = path[i]
50
+ parent = path[i]
49
51
  break
50
52
  }
51
53
  }
52
54
  }
53
55
 
54
- // add to scene if parent is the wrapper node
55
56
  if (
56
- child.metaType === 'standardMeta' &&
57
- child.type !== 'scene' &&
58
- isLunchboxRootNode(effectiveParent)
59
- ) {
60
- // ensure scene exists
61
- const sceneNode = ensuredScene.value
62
-
63
- if (sceneNode.instance && child) {
64
- sceneNode.addChild(child)
65
- }
66
- if (
67
- child.instance &&
68
- child.instance.isObject3D &&
69
- sceneNode.instance
70
- ) {
71
- if (sceneNode !== child) {
72
- sceneNode.instance.add(child.instance)
73
- }
74
- }
75
- }
76
- // add to hierarchy otherwise
77
- else if (
78
57
  isLunchboxStandardNode(child) &&
79
58
  child.instance?.isObject3D &&
80
- isLunchboxStandardNode(effectiveParent) &&
81
- effectiveParent.instance?.isObject3D
59
+ isLunchboxStandardNode(parent) &&
60
+ parent.instance?.isObject3D
82
61
  ) {
83
- effectiveParent.instance?.add?.(child.instance)
62
+ parent.instance?.add?.(child.instance)
84
63
  }
85
64
 
86
65
  // add attached props
@@ -1,10 +1,8 @@
1
- import { allNodes, MiniDom } from '../core'
1
+ import { MiniDom } from '../core'
2
2
  import { isLunchboxStandardNode } from '../utils'
3
- import { overrides } from '../core'
4
3
 
5
4
  export const remove = (node: MiniDom.RendererBaseNode) => {
6
5
  if (!node) return
7
- const overrideKeys = Object.keys(overrides)
8
6
  // prep subtree
9
7
  const subtree: MiniDom.BaseNode[] = []
10
8
  node.walk((descendant) => {
@@ -14,14 +12,6 @@ export const remove = (node: MiniDom.RendererBaseNode) => {
14
12
 
15
13
  // clean up subtree
16
14
  subtree.forEach((n) => {
17
- const overrideKey = overrideKeys.find(
18
- (key) => overrides[key]?.uuid === n.uuid
19
- )
20
- // if this node is an override, remove it from the overrides list
21
- if (overrideKey) {
22
- overrides[overrideKey] = null
23
- }
24
-
25
15
  if (isLunchboxStandardNode(n)) {
26
16
  // try to remove three object
27
17
  n.instance?.removeFromParent?.()
@@ -38,11 +28,5 @@ export const remove = (node: MiniDom.RendererBaseNode) => {
38
28
 
39
29
  // drop tree node
40
30
  n.drop()
41
-
42
- // remove Lunchbox node from main list
43
- const idx = allNodes.findIndex((v) => v.uuid === n.uuid)
44
- if (idx !== -1) {
45
- allNodes.splice(idx, 1)
46
- }
47
31
  })
48
32
  }
package/src/types.ts CHANGED
@@ -1,14 +1,32 @@
1
+ type RendererStandardNode<T = THREE.Object3D> =
2
+ import('./core').MiniDom.RendererStandardNode<T>
1
3
  type RootNode = import('./core/minidom').MiniDom.RendererRootNode
2
4
  type VNodeProps = import('vue').VNodeProps
3
5
  type VueApp<T> = import('vue').App<T>
4
6
  type WatchSource = import('vue').WatchSource
5
- type RendererStandardNode<T = THREE.Object3D> =
6
- import('./core').MiniDom.RendererStandardNode<T>
7
+ type WatchStopHandle = import('vue').WatchStopHandle
8
+ type ThreeCamera = import('three').Camera
9
+ type ThreeRenderer = import('three').Renderer
10
+ type ThreeScene = import('three').Scene
7
11
 
8
12
  export declare namespace Lunch {
9
13
  /** Lunchbox app. */
10
- type App = VueApp<any> & {
14
+ type App = Omit<VueApp<any>, 'config'> & {
11
15
  clearCustomRender: () => void
16
+ config: Omit<VueApp<any>['config'], 'globalProperties'> & {
17
+ globalProperties: {
18
+ lunchbox: {
19
+ afterRender: Lunch.UpdateCallback[]
20
+ beforeRender: Lunch.UpdateCallback[]
21
+ camera: ThreeCamera | null
22
+ dpr: number
23
+ frameId: number
24
+ renderer: ThreeRenderer | null
25
+ scene: ThreeScene | null
26
+ watchStopHandle: WatchStopHandle | null
27
+ }
28
+ } & Record<string, any>
29
+ }
12
30
  customRender: ((opts: UpdateCallbackProperties) => void) | null
13
31
  extend: (v: Record<string, any>) => App
14
32
  rootNode: RootNode
@@ -18,6 +36,14 @@ export declare namespace Lunch {
18
36
  update: UpdateCallback
19
37
  }
20
38
 
39
+ // type AppGlobals = {
40
+ // /** Device pixel resolution */
41
+ // dpr: number
42
+ // }
43
+ type AppGlobals = App['config']['globalProperties']['lunchbox']
44
+
45
+ type AppGlobalsUpdate = (newValue: Partial<AppGlobals>) => void
46
+
21
47
  interface CanvasProps {
22
48
  dpr?: number
23
49
  wrapperProps?: WrapperProps
@@ -34,6 +60,10 @@ export declare namespace Lunch {
34
60
  text: string
35
61
  }
36
62
 
63
+ type CustomRenderFunctionSetter = (
64
+ render: (opts: Lunch.UpdateCallbackProperties) => void
65
+ ) => void
66
+
37
67
  interface DomMeta extends MetaBase {
38
68
  domElement: HTMLElement
39
69
  }
@@ -140,12 +170,14 @@ export declare namespace Lunch {
140
170
 
141
171
  type SizePolicy = 'full' | 'container'
142
172
 
173
+ type Vector3AsArray = [number, number, number]
174
+
143
175
  interface WrapperProps {
144
176
  background?: string
145
177
  cameraArgs?: any[]
146
- cameraLook?: [number, number, number]
147
- cameraLookAt?: [number, number, number]
148
- cameraPosition?: [number, number, number]
178
+ cameraLook?: Vector3AsArray
179
+ cameraLookAt?: Vector3AsArray
180
+ cameraPosition?: Vector3AsArray
149
181
  dpr?: number
150
182
  ortho?: boolean
151
183
  orthographic?: boolean
@@ -1,4 +1,3 @@
1
- import { lunchboxDomComponentNames } from '../components'
2
1
  import { Lunch } from '..'
3
2
 
4
3
  export * from './find'
@@ -32,9 +31,7 @@ export const isLunchboxComponent = (
32
31
  export const isLunchboxDomComponent = (node: any): node is Lunch.DomMeta => {
33
32
  if ((node as Lunch.MetaBase)?.metaType === 'domMeta') return true
34
33
 
35
- const typeToCheck = typeof node === 'string' ? node : node?.type
36
-
37
- return lunchboxDomComponentNames.includes(typeToCheck ?? '')
34
+ return node?.props?.['data-lunchbox']
38
35
  }
39
36
 
40
37
  export const isLunchboxStandardNode = (
package/dist/.DS_Store DELETED
Binary file
package/src/.DS_Store DELETED
Binary file
@@ -1,312 +0,0 @@
1
- import {
2
- h,
3
- ComponentOptions,
4
- getCurrentInstance,
5
- onBeforeUnmount,
6
- onMounted,
7
- ref,
8
- WatchSource,
9
- WritableComputedRef,
10
- } from 'vue'
11
- import {
12
- cameraReady,
13
- cancelUpdate,
14
- cancelUpdateSource,
15
- createNode,
16
- ensuredCamera,
17
- ensureRenderer,
18
- ensuredScene,
19
- fallbackCameraUuid,
20
- fallbackRendererUuid,
21
- MiniDom,
22
- rendererReady,
23
- startCallbacks,
24
- tryGetNodeWithInstanceType,
25
- update,
26
- } from '../../core'
27
- import { set } from 'lodash'
28
- import { globals, Lunch } from '../..'
29
- // import { Color, Vector2, sRGBEncoding, ACESFilmicToneMapping } from 'three'
30
- import * as THREE from 'three'
31
- import { prepCanvas } from './prepCanvas'
32
-
33
- // TODO:
34
- // Continue r3f prop - what else (besides camera fov) makes r3f look good?
35
-
36
- /** fixed & fill styling for container */
37
- const fillStyle = (position: string) => {
38
- return {
39
- position,
40
- top: 0,
41
- right: 0,
42
- bottom: 0,
43
- left: 0,
44
- width: '100%',
45
- height: '100%',
46
- display: 'block',
47
- }
48
- }
49
-
50
- export const LunchboxWrapper: ComponentOptions = {
51
- name: 'Lunchbox',
52
- props: {
53
- // These should match the Lunchbox.WrapperProps interface
54
- background: String,
55
- cameraArgs: Array,
56
- cameraLook: Array,
57
- cameraLookAt: Array,
58
- cameraPosition: Array,
59
- dpr: Number,
60
- ortho: Boolean,
61
- orthographic: Boolean,
62
- r3f: Boolean,
63
- rendererArguments: Object,
64
- rendererProperties: Object,
65
- sizePolicy: String,
66
- shadow: [Boolean, Object],
67
- transparent: Boolean,
68
- zoom: Number,
69
- updateSource: Object,
70
- },
71
- setup(props: Lunch.WrapperProps, context) {
72
- const canvas = ref<MiniDom.RendererDomNode>()
73
- const useFallbackRenderer = ref(true)
74
- const dpr = ref(props.dpr ?? -1)
75
- const container = ref<MiniDom.RendererDomNode>()
76
- let renderer: Lunch.Node<THREE.WebGLRenderer> | null
77
- let camera: Lunch.Node<THREE.Camera> | null
78
- let scene: MiniDom.RendererStandardNode<THREE.Scene>
79
-
80
- // https://threejs.org/docs/index.html#manual/en/introduction/Color-management
81
- if (props.r3f && (THREE as any)?.ColorManagement) {
82
- ;(THREE as any).ColorManagement.legacyMode = false
83
- }
84
-
85
- // MOUNT
86
- // ====================
87
- onMounted(() => {
88
- // canvas needs to exist
89
- if (!canvas.value) throw new Error('missing canvas')
90
-
91
- // RENDERER
92
- // ====================
93
- // is there already a renderer?
94
- // TODO: allow other renderer types
95
- renderer = tryGetNodeWithInstanceType([
96
- 'WebGLRenderer',
97
- ]) as unknown as Lunch.Node<THREE.WebGLRenderer> | null
98
-
99
- // if renderer is missing, initialize with options
100
- if (!renderer) {
101
- // build renderer args
102
- const rendererArgs: THREE.WebGLRendererParameters = {
103
- alpha: props.transparent,
104
- antialias: true,
105
- canvas: canvas.value.domElement,
106
- powerPreference: !!props.r3f
107
- ? 'high-performance'
108
- : 'default',
109
- ...(props.rendererArguments ?? {}),
110
- }
111
-
112
- // create new renderer
113
- ensureRenderer.value = createNode<THREE.WebGLRenderer>({
114
- type: 'WebGLRenderer',
115
- uuid: fallbackRendererUuid,
116
- props: {
117
- args: [rendererArgs],
118
- },
119
- })
120
-
121
- // we've initialized the renderer, so anything depending on it can execute now
122
- rendererReady.value = true
123
-
124
- const rendererAsWebGlRenderer =
125
- ensureRenderer as WritableComputedRef<
126
- Lunch.Node<THREE.WebGLRenderer>
127
- >
128
-
129
- // apply r3f settings if desired
130
- if (props.r3f) {
131
- if (rendererAsWebGlRenderer.value.instance) {
132
- rendererAsWebGlRenderer.value.instance.outputEncoding =
133
- THREE.sRGBEncoding
134
- rendererAsWebGlRenderer.value.instance.toneMapping =
135
- THREE.ACESFilmicToneMapping
136
- }
137
- }
138
-
139
- // update render sugar
140
- const sugar = {
141
- shadow: props.shadow,
142
- }
143
- if (rendererAsWebGlRenderer.value.instance && sugar?.shadow) {
144
- rendererAsWebGlRenderer.value.instance.shadowMap.enabled =
145
- true
146
- if (typeof sugar.shadow === 'object') {
147
- rendererAsWebGlRenderer.value.instance.shadowMap.type =
148
- sugar.shadow.type
149
- }
150
- }
151
-
152
- // set renderer props if needed
153
- if (props.rendererProperties) {
154
- Object.keys(props.rendererProperties).forEach((key) => {
155
- set(
156
- rendererAsWebGlRenderer.value,
157
- key,
158
- (props.rendererProperties as any)[key]
159
- )
160
- })
161
- }
162
-
163
- // update using created renderer
164
- renderer = rendererAsWebGlRenderer.value
165
- } else {
166
- useFallbackRenderer.value = false
167
- // the user has initialized the renderer, so anything depending
168
- // on the renderer can execute
169
- rendererReady.value = true
170
- }
171
-
172
- // CAMERA
173
- // ====================
174
- // is there already a camera?
175
- camera = tryGetNodeWithInstanceType([
176
- 'PerspectiveCamera',
177
- 'OrthographicCamera',
178
- ])
179
- // if not, let's create one
180
- if (!camera) {
181
- // create ortho camera
182
- if (props.ortho || props.orthographic) {
183
- ensuredCamera.value = createNode<THREE.OrthographicCamera>({
184
- props: { args: props.cameraArgs ?? [] },
185
- type: 'OrthographicCamera',
186
- uuid: fallbackCameraUuid,
187
- })
188
- } else {
189
- ensuredCamera.value = createNode<THREE.PerspectiveCamera>({
190
- props: {
191
- args: props.cameraArgs ?? [
192
- props.r3f ? 75 : 45,
193
- 0.5625,
194
- 1,
195
- 1000,
196
- ],
197
- },
198
- type: 'PerspectiveCamera',
199
- uuid: fallbackCameraUuid,
200
- })
201
- }
202
-
203
- cameraReady.value = true
204
-
205
- camera = ensuredCamera.value
206
- } else {
207
- cameraReady.value = true
208
- }
209
- if (!camera.instance) {
210
- throw new Error('Error creating camera.')
211
- }
212
- // move camera if needed
213
- if (camera && props.cameraPosition) {
214
- camera.instance.position.set(...props.cameraPosition)
215
- }
216
- // angle camera if needed
217
- if (camera && (props.cameraLookAt || props.cameraLook)) {
218
- const source = (props.cameraLookAt || props.cameraLook)!
219
- camera.instance.lookAt(...source)
220
- }
221
- // zoom camera if needed
222
- if (camera && props.zoom !== undefined) {
223
- ;(camera.instance as THREE.OrthographicCamera).zoom = props.zoom
224
- }
225
-
226
- // SCENE
227
- // ====================
228
- scene = ensuredScene.value
229
- // set background color
230
- if (scene && scene.instance && props.background) {
231
- scene.instance.background = new THREE.Color(props.background)
232
- }
233
-
234
- // MISC PROPERTIES
235
- // ====================
236
- if (dpr.value === -1) {
237
- dpr.value = window.devicePixelRatio
238
- }
239
-
240
- if (renderer?.instance) {
241
- renderer.instance.setPixelRatio(dpr.value)
242
- globals.dpr.value = dpr.value
243
- // prep canvas (sizing, observe, unmount, etc)
244
- prepCanvas(
245
- container,
246
- renderer.instance.domElement,
247
- onBeforeUnmount,
248
- props.sizePolicy,
249
- )
250
- } else {
251
- throw new Error('missing renderer')
252
- }
253
-
254
- // CALLBACK PREP
255
- // ====================
256
- const app = getCurrentInstance()!.appContext.app as Lunch.App
257
-
258
- // START
259
- // ====================
260
- for (let startCallback of startCallbacks) {
261
- startCallback({
262
- app,
263
- camera: camera.instance,
264
- renderer: renderer.instance,
265
- scene: scene.instance,
266
- })
267
- }
268
-
269
- // KICK UPDATE
270
- // ====================
271
- update({
272
- app,
273
- camera: camera.instance,
274
- renderer: renderer.instance,
275
- scene: scene.instance,
276
- updateSource: props.updateSource,
277
- })
278
- })
279
-
280
- // UNMOUNT
281
- // ====================
282
- onBeforeUnmount(() => {
283
- cancelUpdate()
284
- cancelUpdateSource()
285
- })
286
-
287
- // RENDER FUNCTION
288
- // ====================
289
- const containerFillStyle = props.sizePolicy === 'container' ? 'static' : 'absolute'
290
- const canvasFillStyle = props.sizePolicy === 'container' ? 'static' : 'fixed'
291
-
292
- return () => [
293
- context.slots.default?.() ?? null,
294
- h(
295
- 'div',
296
- {
297
- style: fillStyle(containerFillStyle),
298
- ref: container,
299
- },
300
- [
301
- useFallbackRenderer.value
302
- ? h('canvas', {
303
- style: fillStyle(canvasFillStyle),
304
- class: 'lunchbox-canvas',
305
- ref: canvas,
306
- })
307
- : null,
308
- ]
309
- ),
310
- ]
311
- },
312
- }
Binary file
@@ -1,4 +0,0 @@
1
- import { MiniDom } from '.'
2
-
3
- // this needs to be in a separate file to ensure it's created immediately
4
- export const allNodes = [] as Array<MiniDom.BaseNode>
package/src/core/start.ts DELETED
@@ -1,11 +0,0 @@
1
- import { Lunch } from '..'
2
-
3
- export const startCallbacks = [] as Lunch.UpdateCallback[]
4
-
5
- export const onStart = (cb: Lunch.UpdateCallback, index = Infinity) => {
6
- if (index === Infinity) {
7
- startCallbacks.push(cb)
8
- } else {
9
- startCallbacks.splice(index, 0, cb)
10
- }
11
- }