@lukekaalim/act-three 5.6.4 → 5.8.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.
- package/objects.js +7 -5
- package/package.json +4 -4
- package/props.js +120 -63
- package/reconciler.js +49 -18
- package/renderer.js +44 -31
package/objects.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// @flow strict
|
|
2
|
-
/*:: import type {
|
|
3
|
-
/*:: import type { PropDiff } from '@lukekaalim/act-reconciler'; */
|
|
2
|
+
/*:: import type { PropDiff } from '@lukekaalim/act-renderer-core'; */
|
|
4
3
|
import {
|
|
5
4
|
Group,
|
|
6
5
|
Mesh,
|
|
@@ -20,12 +19,14 @@ import {
|
|
|
20
19
|
Bone,
|
|
21
20
|
Sprite,
|
|
22
21
|
LOD,
|
|
22
|
+
Object3D,
|
|
23
23
|
} from "three";
|
|
24
24
|
|
|
25
25
|
export const threeObjectClasses/*: { [string]: Class<Object3D> }*/ = Object.fromEntries(Object.entries({
|
|
26
26
|
// grouping
|
|
27
27
|
Scene,
|
|
28
28
|
Group,
|
|
29
|
+
Object3D,
|
|
29
30
|
|
|
30
31
|
// lights
|
|
31
32
|
DirectionalLight,
|
|
@@ -55,12 +56,13 @@ export const threeObjectClasses/*: { [string]: Class<Object3D> }*/ = Object.from
|
|
|
55
56
|
LOD,
|
|
56
57
|
}).map(([key, value]) => [key.toLowerCase(), (value/*: any*/)]));
|
|
57
58
|
|
|
58
|
-
|
|
59
|
+
class UnsupportedObjectTypeError extends Error {}
|
|
60
|
+
|
|
61
|
+
export const createObject = (type/*: string*/)/*: Object3D*/ => {
|
|
59
62
|
const objectClass = threeObjectClasses[type.toLowerCase()];
|
|
60
63
|
|
|
61
64
|
if (!objectClass) {
|
|
62
|
-
|
|
63
|
-
return null;
|
|
65
|
+
throw new UnsupportedObjectTypeError()
|
|
64
66
|
}
|
|
65
67
|
|
|
66
68
|
return new objectClass();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lukekaalim/act-three",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.8.0",
|
|
4
4
|
"description": "Render threejs content using act",
|
|
5
5
|
"main": "entry.js",
|
|
6
6
|
"type": "module",
|
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
"author": "Luke Kaalim",
|
|
13
13
|
"license": "ISC",
|
|
14
14
|
"peerDependencies": {
|
|
15
|
-
"three": "^0.
|
|
15
|
+
"three": "^0.149.0"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@lukekaalim/act": "^2.
|
|
18
|
+
"@lukekaalim/act": "^2.5.0",
|
|
19
|
+
"@lukekaalim/act-reconciler": "^3.1.0",
|
|
19
20
|
"@lukekaalim/act-renderer-core": "^3.2.2",
|
|
20
|
-
"@lukekaalim/act-reconciler": "^3.0.1",
|
|
21
21
|
"@lukekaalim/act-web": "^2.0.1"
|
|
22
22
|
}
|
|
23
23
|
}
|
package/props.js
CHANGED
|
@@ -1,78 +1,135 @@
|
|
|
1
1
|
// @flow strict
|
|
2
|
-
/*:: import type {
|
|
3
|
-
/*::
|
|
2
|
+
/*:: import type { WebGLRenderer, LightShadow } from "three"; */
|
|
3
|
+
/*::
|
|
4
|
+
import type { Props } from '@lukekaalim/act';
|
|
5
|
+
import type { PropDiff, PropDiffRegistry } from '@lukekaalim/act-renderer-core';
|
|
6
|
+
import type { CommitDiff, Diff3, DiffSet } from '@lukekaalim/act-reconciler';
|
|
7
|
+
*/
|
|
4
8
|
|
|
5
|
-
import { calculatePropsDiff } from
|
|
9
|
+
import { calculatePropsDiff, setRef2 } from '@lukekaalim/act-renderer-core'
|
|
6
10
|
import { setHTMLProp } from "@lukekaalim/act-web";
|
|
7
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
BufferGeometry,
|
|
13
|
+
Camera,
|
|
14
|
+
DirectionalLight,
|
|
15
|
+
Euler,
|
|
16
|
+
Group,
|
|
17
|
+
Light,
|
|
18
|
+
Material,
|
|
19
|
+
Matrix3,
|
|
20
|
+
Matrix4,
|
|
21
|
+
Object3D,
|
|
22
|
+
OrthographicCamera,
|
|
23
|
+
Quaternion,
|
|
24
|
+
Vector2,
|
|
25
|
+
Vector3,
|
|
26
|
+
} from "three";
|
|
8
27
|
import { setRef } from "@lukekaalim/act-renderer-core";
|
|
9
28
|
|
|
10
|
-
export const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
29
|
+
export const setTransformProp = (target/*: mixed*/, diff/*: PropDiff*/)/*: boolean*/ => {
|
|
30
|
+
if (target instanceof Vector2 && diff.next instanceof Vector2) {
|
|
31
|
+
target.copy(diff.next);
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
if (target instanceof Vector3 && diff.next instanceof Vector3) {
|
|
35
|
+
target.copy(diff.next);
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
if (target instanceof Matrix3 && diff.next instanceof Matrix3) {
|
|
39
|
+
target.copy(diff.next);
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
if (target instanceof Matrix4 && diff.next instanceof Matrix4) {
|
|
43
|
+
target.copy(diff.next);
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
if (target instanceof Quaternion && diff.next instanceof Quaternion) {
|
|
47
|
+
target.copy(diff.next);
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
if (target instanceof Euler && diff.next instanceof Euler) {
|
|
51
|
+
target.copy(diff.next);
|
|
52
|
+
return true;
|
|
24
53
|
}
|
|
25
|
-
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
export const setValueProp = (object/*: { [string]: mixed }*/, name/*: string*/, diff/*: PropDiff*/)/*: boolean*/ => {
|
|
57
|
+
if (typeof object[name] !== typeof diff.next)
|
|
58
|
+
return false;
|
|
26
59
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
60
|
+
switch (typeof object[name]) {
|
|
61
|
+
case 'string':
|
|
62
|
+
case 'number':
|
|
63
|
+
case 'boolean':
|
|
64
|
+
object[name] = diff.next;
|
|
65
|
+
return true;
|
|
66
|
+
default:
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export const setMeshProp = (object/*: { [string]: mixed }*/, name/*: string*/, diff/*: PropDiff*/)/*: boolean*/ => {
|
|
71
|
+
if (object[name] instanceof BufferGeometry && diff.next instanceof BufferGeometry) {
|
|
72
|
+
object[name] = diff.next;
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
if (object[name] instanceof Material && diff.next instanceof Material) {
|
|
76
|
+
object[name] = diff.next;
|
|
77
|
+
return true;
|
|
40
78
|
}
|
|
41
|
-
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
42
81
|
|
|
43
|
-
export const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
82
|
+
export const setLightShadowProps = (
|
|
83
|
+
diffs/*: PropDiffRegistry*/,
|
|
84
|
+
lightShadow/*: LightShadow*/,
|
|
85
|
+
) => {
|
|
86
|
+
for (const [key, propDiff] of diffs.map) {
|
|
87
|
+
const target = (lightShadow/*: any*/)[key];
|
|
88
|
+
if (setTransformProp(target, propDiff))
|
|
89
|
+
continue;
|
|
90
|
+
if (setValueProp((lightShadow/*: any*/), key, propDiff))
|
|
91
|
+
continue;
|
|
92
|
+
if (target instanceof Object3D) {
|
|
93
|
+
if (propDiff.next instanceof Object3D) {
|
|
94
|
+
(lightShadow/*: any*/)[key] = propDiff.next;
|
|
95
|
+
continue;
|
|
52
96
|
}
|
|
53
|
-
|
|
54
|
-
|
|
97
|
+
const propRegistry = calculatePropsDiff((propDiff.prev/*: any*/) || {}, (propDiff.next/*: any*/) || {});
|
|
98
|
+
setObjectProps2(propRegistry, target);
|
|
99
|
+
continue;
|
|
55
100
|
}
|
|
101
|
+
|
|
102
|
+
console.warn(`Unhandled prop ${key}`, propDiff.next, target);
|
|
56
103
|
}
|
|
57
104
|
}
|
|
58
105
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
106
|
+
const skipProps = new Set(['ref', 'key', 'children'])
|
|
107
|
+
|
|
108
|
+
export const setObjectProps2 = (
|
|
109
|
+
diff/*: PropDiffRegistry*/,
|
|
110
|
+
object/*: Object3D*/,
|
|
111
|
+
) => {
|
|
112
|
+
for (const [key, propDiff] of diff.map) {
|
|
113
|
+
if (skipProps.has(key))
|
|
114
|
+
continue;
|
|
115
|
+
|
|
116
|
+
const target = (object/*: any*/)[key];
|
|
117
|
+
if (key === 'shadow' && object instanceof Light) {
|
|
118
|
+
const propRegistry = calculatePropsDiff((propDiff.prev/*: any*/) || {}, (propDiff.next/*: any*/) || {});
|
|
119
|
+
setLightShadowProps(propRegistry, target)
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (setMeshProp((object/*: any*/), key, propDiff)) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (setTransformProp(target, propDiff))
|
|
126
|
+
continue;
|
|
127
|
+
if (setValueProp((object/*: any*/), key, propDiff))
|
|
128
|
+
continue;
|
|
129
|
+
|
|
130
|
+
console.warn(`Unhandled prop ${key}`, propDiff.next, object);
|
|
77
131
|
}
|
|
78
|
-
|
|
132
|
+
|
|
133
|
+
if (object instanceof OrthographicCamera)
|
|
134
|
+
object.updateProjectionMatrix();
|
|
135
|
+
}
|
package/reconciler.js
CHANGED
|
@@ -2,31 +2,62 @@
|
|
|
2
2
|
/*:: import type { Element } from '@lukekaalim/act'; */
|
|
3
3
|
/*:: import type { Renderer } from '@lukekaalim/act-renderer-core'; */
|
|
4
4
|
|
|
5
|
-
import { createTree } from "@lukekaalim/act-reconciler";
|
|
5
|
+
import { createBoundaryService, createEffectService, createReconciler, createSchedule2, createTree, createTreeService2 } from "@lukekaalim/act-reconciler";
|
|
6
|
+
import { createNullRenderer2 } from "@lukekaalim/act-renderer-core";
|
|
6
7
|
import { createWebRenderer, setNodeChildren } from "@lukekaalim/act-web";
|
|
8
|
+
import { setNodeChildren2 } from "@lukekaalim/act-web/node";
|
|
7
9
|
|
|
8
|
-
import {
|
|
10
|
+
import { createObjectRenderer } from "./renderer.js";
|
|
9
11
|
|
|
10
12
|
export const render = (element/*: Element*/, node/*: HTMLElement*/) => {
|
|
13
|
+
const webToThree = createNullRenderer2(() => object, ['three']);
|
|
14
|
+
const threeToWeb = createNullRenderer2(() => web, ['web']);
|
|
11
15
|
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
const object = createObjectRenderer((type) => {
|
|
17
|
+
switch (type) {
|
|
18
|
+
case 'web':
|
|
19
|
+
return threeToWeb;
|
|
20
|
+
default:
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
const web = createWebRenderer(type => {
|
|
25
|
+
switch (type) {
|
|
15
26
|
case 'scene':
|
|
16
|
-
|
|
27
|
+
case 'three':
|
|
28
|
+
return webToThree;
|
|
17
29
|
default:
|
|
18
|
-
return
|
|
30
|
+
return null;
|
|
19
31
|
}
|
|
20
32
|
});
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
|
|
34
|
+
const scheduler = createSchedule2((callback) => {
|
|
35
|
+
const id = requestAnimationFrame(() => callback(5));
|
|
36
|
+
return () => cancelAnimationFrame(id);
|
|
37
|
+
})
|
|
38
|
+
const effect = createEffectService(scheduler);
|
|
39
|
+
const boundary = createBoundaryService();
|
|
40
|
+
|
|
41
|
+
const reconciler = createReconciler(scheduler);
|
|
42
|
+
|
|
43
|
+
reconciler.diff.subscribeDiff(set => {
|
|
44
|
+
performance.mark('act:three:nodes:start')
|
|
45
|
+
const children = web.render(set, set.root);
|
|
46
|
+
setNodeChildren2(node, children);
|
|
47
|
+
performance.mark('act:three:nodes:end')
|
|
48
|
+
performance.measure('act:three:nodes', 'act:three:nodes:start', 'act:three:nodes:end')
|
|
49
|
+
|
|
50
|
+
performance.mark('act:three:effects:start')
|
|
51
|
+
reconciler.tree.live.registry = effect.runEffectRegistry(set.registry);
|
|
52
|
+
performance.mark('act:three:effects:end')
|
|
53
|
+
performance.measure('act:three:effects', 'act:three:effects:start', 'act:three:effects:end')
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
performance.mark('act:three:suspense:start')
|
|
57
|
+
const map = boundary.calcBoundaryMap(set);
|
|
58
|
+
boundary.getRootBoundaryValue(set.suspensions, set, map);
|
|
59
|
+
performance.mark('act:three:suspense:end')
|
|
60
|
+
performance.measure('act:three:suspense', 'act:three:suspense:start', 'act:three:suspense:end')
|
|
61
|
+
})
|
|
62
|
+
reconciler.tree.mount(element);
|
|
32
63
|
};
|
package/renderer.js
CHANGED
|
@@ -1,48 +1,61 @@
|
|
|
1
1
|
// @flow strict
|
|
2
|
-
/*:: import type { Renderer, RenderResult} from '@lukekaalim/act-renderer-core'; */
|
|
3
|
-
/*:: import type { Component } from '@lukekaalim/act'; */
|
|
4
|
-
/*:: import type { CommitDiff,
|
|
5
|
-
/*::
|
|
6
|
-
import {
|
|
2
|
+
/*:: import type { Renderer, RenderResult, PropDiff } from '@lukekaalim/act-renderer-core'; */
|
|
3
|
+
/*:: import type { Component, ElementType } from '@lukekaalim/act'; */
|
|
4
|
+
/*:: import type { CommitDiff, CommitID } from '@lukekaalim/act-reconciler'; */
|
|
5
|
+
/*::
|
|
6
|
+
import type { Object3D } from 'three';
|
|
7
|
+
import type { Renderer2 } from "../core/renderer2";
|
|
8
|
+
*/
|
|
9
|
+
import { calculatePropsDiff, createManagedRenderer, createNullRenderer, createNullRenderer2, setRef2 } from '@lukekaalim/act-renderer-core';
|
|
10
|
+
import { createRenderer2 } from '@lukekaalim/act-renderer-core/renderer2';
|
|
7
11
|
import { createObject } from "./objects";
|
|
8
|
-
import {
|
|
12
|
+
import { setObjectProps2 } from "./props";
|
|
9
13
|
|
|
10
14
|
export const createObjectRenderer = (
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
)
|
|
15
|
-
|
|
15
|
+
getNextRenderer/*: null | ((type: ElementType) => null | Renderer2<Object3D>)*/ = null
|
|
16
|
+
)/*: Renderer2<Object3D>*/ => {
|
|
17
|
+
|
|
18
|
+
const getRenderer = (set, commitId) => {
|
|
19
|
+
const commit = set.nexts.get(commitId);
|
|
20
|
+
return getNextRenderer && getNextRenderer(commit.element.type) || objectRenderer;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const getNodes = (set, commitId) => {
|
|
24
|
+
const renderer = getRenderer(set, commitId)
|
|
25
|
+
return renderer.getNodes(set, commitId);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const render = (set, commitId) => {
|
|
29
|
+
const renderer = getRenderer(set, commitId)
|
|
30
|
+
return renderer.render(set, commitId);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const objectRenderer = createRenderer2({
|
|
16
34
|
remove(object) {
|
|
17
35
|
object.removeFromParent();
|
|
18
36
|
},
|
|
19
|
-
update(object,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
37
|
+
update(object, set, diff) {
|
|
38
|
+
setRef2(object, diff.commit, diff.change);
|
|
39
|
+
const prev = set.prevs.map.get(diff.commit.id);
|
|
40
|
+
const propDiff = calculatePropsDiff(prev ? prev.element.props : {}, diff.commit.element.props)
|
|
41
|
+
setObjectProps2(propDiff, object);
|
|
42
|
+
},
|
|
43
|
+
create(type) {
|
|
44
|
+
return createObject(type);
|
|
45
|
+
},
|
|
46
|
+
attach(object, set, diff, children) {
|
|
23
47
|
const missingChildren = children
|
|
24
|
-
.map(c => c.node)
|
|
25
48
|
.filter(n => n.parent !== object);
|
|
49
|
+
|
|
26
50
|
if (missingChildren.length > 0)
|
|
27
51
|
object.add(...missingChildren);
|
|
28
|
-
},
|
|
29
|
-
add(diff) {
|
|
30
|
-
if (typeof diff.next.element.type === 'function')
|
|
31
|
-
return null;
|
|
32
|
-
if (diff.next.element.type === 'act:context')
|
|
33
|
-
return null;
|
|
34
|
-
return create(diff.next.element.type);
|
|
35
|
-
},
|
|
36
|
-
next(diff, parent) {
|
|
37
|
-
if (next)
|
|
38
|
-
return next(diff, parent)
|
|
39
|
-
return objectRenderer.render(diff);
|
|
40
52
|
}
|
|
41
|
-
});
|
|
53
|
+
}, { getNodes, render });
|
|
54
|
+
|
|
42
55
|
return objectRenderer;
|
|
43
56
|
};
|
|
44
57
|
|
|
45
|
-
export const createSceneRenderer = /*:: <T>*/()/*:
|
|
58
|
+
export const createSceneRenderer = /*:: <T>*/()/*: Renderer2<T>*/ => {
|
|
46
59
|
const object = createObjectRenderer();
|
|
47
|
-
return
|
|
60
|
+
return createNullRenderer2(object);
|
|
48
61
|
}
|