vuer 0.0.16__py3-none-any.whl → 0.0.18__py3-none-any.whl
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.
Potentially problematic release.
This version of vuer might be problematic. Click here for more details.
- vuer/__pycache__/events.cpython-38.pyc +0 -0
- vuer/__pycache__/server.cpython-38.pyc +0 -0
- vuer/__pycache__/types.cpython-38.pyc +0 -0
- vuer/events.py +4 -3
- vuer/schemas/__init__.py +3 -0
- vuer/schemas/__pycache__/__init__.cpython-38.pyc +0 -0
- vuer/schemas/__pycache__/drei_components.cpython-38.pyc +0 -0
- vuer/schemas/__pycache__/html_components.cpython-38.pyc +0 -0
- vuer/schemas/__pycache__/scene_components.cpython-38.pyc +0 -0
- vuer/schemas/drei_components.py +171 -0
- vuer/schemas/html_components.py +253 -0
- vuer/schemas/scene_components.py +522 -0
- vuer/server.py +64 -18
- vuer/types.py +21 -19
- {vuer-0.0.16.dist-info → vuer-0.0.18.dist-info}/METADATA +1 -1
- vuer-0.0.18.dist-info/RECORD +37 -0
- vuer-0.0.16.dist-info/RECORD +0 -29
- {vuer-0.0.16.dist-info → vuer-0.0.18.dist-info}/LICENSE +0 -0
- {vuer-0.0.16.dist-info → vuer-0.0.18.dist-info}/WHEEL +0 -0
- {vuer-0.0.16.dist-info → vuer-0.0.18.dist-info}/entry_points.txt +0 -0
- {vuer-0.0.16.dist-info → vuer-0.0.18.dist-info}/top_level.txt +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
vuer/events.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
from typing import List,
|
|
1
|
+
from typing import List, Tuple
|
|
2
2
|
from uuid import uuid4
|
|
3
3
|
|
|
4
|
-
from vuer.schemas import
|
|
4
|
+
from vuer.schemas import Scene
|
|
5
|
+
from vuer.schemas import Element
|
|
5
6
|
from vuer.serdes import serializer
|
|
6
7
|
|
|
7
8
|
|
|
@@ -124,7 +125,7 @@ class Update(ServerEvent):
|
|
|
124
125
|
|
|
125
126
|
etype = "UPDATE"
|
|
126
127
|
|
|
127
|
-
def __init__(self, *elements:
|
|
128
|
+
def __init__(self, *elements: Element, strict=False):
|
|
128
129
|
# tuple is not serializable
|
|
129
130
|
super().__init__({"nodes": elements}, strict=strict)
|
|
130
131
|
|
vuer/schemas/__init__.py
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
from vuer.schemas.scene_components import SceneElement
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Html(SceneElement):
|
|
5
|
+
tag = "Html"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Splat(SceneElement):
|
|
9
|
+
tag = "Splat"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Line(SceneElement):
|
|
13
|
+
"""
|
|
14
|
+
Renders a THREE.Line2 or THREE.LineSegments2 (depending on the value of segments).
|
|
15
|
+
|
|
16
|
+
Usage::
|
|
17
|
+
|
|
18
|
+
<Line
|
|
19
|
+
points={[[0, 0, 0], ...]} // Array of points, Array<Vector3 | Vector2 | [number, number, number] | [number, number] | number>
|
|
20
|
+
color="black" // Default
|
|
21
|
+
lineWidth={1} // In pixels (default)
|
|
22
|
+
segments // If true, renders a THREE.LineSegments2. Otherwise, renders a THREE.Line2
|
|
23
|
+
dashed={false} // Default
|
|
24
|
+
vertexColors={[[0, 0, 0], ...]} // Optional array of RGB values for each point
|
|
25
|
+
{...lineProps} // All THREE.Line2 props are valid
|
|
26
|
+
{...materialProps} // All THREE.LineMaterial props are valid
|
|
27
|
+
/>
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
tag = "Line"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class QuadraticBezierLine(SceneElement):
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
Renders a THREE.Line2 using THREE.QuadraticBezierCurve3 for interpolation.
|
|
37
|
+
|
|
38
|
+
Usage::
|
|
39
|
+
|
|
40
|
+
<QuadraticBezierLine
|
|
41
|
+
start={[0, 0, 0]} // Starting point, can be an array or a vec3
|
|
42
|
+
end={[10, 0, 10]} // Ending point, can be an array or a vec3
|
|
43
|
+
mid={[5, 0, 5]} // Optional control point, can be an array or a vec3
|
|
44
|
+
color="black" // Default
|
|
45
|
+
lineWidth={1} // In pixels (default)
|
|
46
|
+
dashed={false} // Default
|
|
47
|
+
vertexColors={[[0, 0, 0], ...]} // Optional array of RGB values for each point
|
|
48
|
+
{...lineProps} // All THREE.Line2 props are valid
|
|
49
|
+
{...materialProps} // All THREE.LineMaterial props are valid
|
|
50
|
+
/>
|
|
51
|
+
|
|
52
|
+
You can also update the line runtime.
|
|
53
|
+
|
|
54
|
+
code::
|
|
55
|
+
|
|
56
|
+
const ref = useRef()
|
|
57
|
+
useFrame((state) => {
|
|
58
|
+
ref.current.setPoints(
|
|
59
|
+
[0, 0, 0],
|
|
60
|
+
[10, 0, 0],
|
|
61
|
+
// [5, 0, 0] // Optional: mid-point
|
|
62
|
+
)
|
|
63
|
+
}, [])
|
|
64
|
+
return <QuadraticBezierLine ref={ref} />
|
|
65
|
+
}
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
tag = "QuadraticBezierLine"
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class CubicBezierLine(SceneElement):
|
|
72
|
+
"""
|
|
73
|
+
Renders a THREE.Line2 using THREE.CubicBezierCurve3 for interpolation.
|
|
74
|
+
|
|
75
|
+
Usage::
|
|
76
|
+
|
|
77
|
+
<CubicBezierLine
|
|
78
|
+
start={[0, 0, 0]} // Starting point
|
|
79
|
+
end={[10, 0, 10]} // Ending point
|
|
80
|
+
midA={[5, 0, 0]} // First control point
|
|
81
|
+
midB={[0, 0, 5]} // Second control point
|
|
82
|
+
color="black" // Default
|
|
83
|
+
lineWidth={1} // In pixels (default)
|
|
84
|
+
dashed={false} // Default
|
|
85
|
+
vertexColors={[[0, 0, 0], ...]} // Optional array of RGB values for each point
|
|
86
|
+
{...lineProps} // All THREE.Line2 props are valid
|
|
87
|
+
{...materialProps} // All THREE.LineMaterial props are valid
|
|
88
|
+
/>
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
tag = "CubicBezierLine"
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class CatmullRomLine(SceneElement):
|
|
95
|
+
"""
|
|
96
|
+
Renders a THREE.Line2 using THREE.CatmullRomCurve3 for interpolation.
|
|
97
|
+
|
|
98
|
+
Usage::
|
|
99
|
+
|
|
100
|
+
<CatmullRomLine
|
|
101
|
+
points={[[0, 0, 0], ...]} // Array of Points
|
|
102
|
+
closed={false} // Default
|
|
103
|
+
curveType="centripetal" // One of "centripetal" (default), "chordal", or "catmullrom"
|
|
104
|
+
tension={0.5} // Default (only applies to "catmullrom" curveType)
|
|
105
|
+
color="black" // Default
|
|
106
|
+
lineWidth={1} // In pixels (default)
|
|
107
|
+
dashed={false} // Default
|
|
108
|
+
vertexColors={[[0, 0, 0], ...]} // Optional array of RGB values for each point
|
|
109
|
+
{...lineProps} // All THREE.Line2 props are valid
|
|
110
|
+
{...materialProps} // All THREE.LineMaterial props are valid
|
|
111
|
+
/>
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
tag = "CatmullRomLine"
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class Facemesh(SceneElement):
|
|
118
|
+
"""Renders an oriented MediaPipe face mesh:
|
|
119
|
+
|
|
120
|
+
:param points: An array of 468+ keypoints as returned by google/mediapipe tasks-vision. Defaults to a sample face.
|
|
121
|
+
:type points: MediaPipePoints, optional
|
|
122
|
+
:param face: An face object as returned by tensorflow/tfjs-models face-landmarks-detection. This parameter is deprecated.
|
|
123
|
+
:type face: MediaPipeFaceMesh, optional
|
|
124
|
+
:param width: Constant width of the mesh. Defaults to undefined.
|
|
125
|
+
:type width: int, optional
|
|
126
|
+
:param height: Constant height of the mesh. Defaults to undefined.
|
|
127
|
+
:type height: int, optional
|
|
128
|
+
:param depth: Constant depth of the mesh. Defaults to 1.
|
|
129
|
+
:type depth: int, optional
|
|
130
|
+
:param verticalTri: A landmarks tri supposed to be vertical. Defaults to [159, 386, 200]. See: https://github.com/tensorflow/tfjs-models/tree/master/face-landmarks-detection#mediapipe-facemesh-keypoints
|
|
131
|
+
:type verticalTri: Tuple[int, int, int], optional
|
|
132
|
+
:param origin: A landmark index (to get the position from) or a vec3 to be the origin of the mesh. Defaults to undefined (i.e., the bbox center).
|
|
133
|
+
:type origin: Union[int, THREE.Vector3], optional
|
|
134
|
+
:param facialTransformationMatrix: A facial transformation matrix, as returned by FaceLandmarkerResult.facialTransformationMatrixes. See: https://developers.google.com/mediapipe/solutions/vision/face_landmarker/web_js#handle_and_display_results
|
|
135
|
+
:type facialTransformationMatrix: FacemeshDatas.SAMPLE_FACELANDMARKER_RESULT.facialTransformationMatrixes[0], optional
|
|
136
|
+
:param offset: Apply position offset extracted from `facialTransformationMatrix`.
|
|
137
|
+
:type offset: bool, optional
|
|
138
|
+
:param offsetScalar: Offset sensitivity factor, less is more sensible.
|
|
139
|
+
:type offsetScalar: float, optional
|
|
140
|
+
:param faceBlendshapes: Face blendshapes, as returned by FaceLandmarkerResult.faceBlendshapes. See: https://developers.google.com/mediapipe/solutions/vision/face_landmarker/web_js#handle_and_display_results
|
|
141
|
+
:type faceBlendshapes: FacemeshDatas.SAMPLE_FACELANDMARKER_RESULT.faceBlendshapes[0], optional
|
|
142
|
+
:param eyes: Whether to enable eyes (note: `faceBlendshapes` is required for this). Defaults to True.
|
|
143
|
+
:type eyes: bool, optional
|
|
144
|
+
|
|
145
|
+
Usage::
|
|
146
|
+
|
|
147
|
+
const faceLandmarkerResult = {
|
|
148
|
+
"faceLandmarks": [
|
|
149
|
+
[
|
|
150
|
+
{ "x": 0.5760777592658997, "y": 0.8639070391654968, "z": -0.030997956171631813 },
|
|
151
|
+
{ "x": 0.572094738483429, "y": 0.7886289358139038, "z": -0.07189624011516571 },
|
|
152
|
+
// ...
|
|
153
|
+
],
|
|
154
|
+
// ...
|
|
155
|
+
],
|
|
156
|
+
"faceBlendshapes": [
|
|
157
|
+
// ...
|
|
158
|
+
],
|
|
159
|
+
"facialTransformationMatrixes": [
|
|
160
|
+
// ...
|
|
161
|
+
]
|
|
162
|
+
},
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const points = faceLandmarkerResult.faceLandmarks[0]
|
|
166
|
+
|
|
167
|
+
<Facemesh points={points} />
|
|
168
|
+
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
tag = "Facemesh"
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from PIL import Image as pil_image
|
|
5
|
+
|
|
6
|
+
from vuer.serdes import IMAGE_FORMATS
|
|
7
|
+
|
|
8
|
+
element_count = 0
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Element:
|
|
12
|
+
"""
|
|
13
|
+
Base class for all elements
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
tag: str = "div"
|
|
17
|
+
|
|
18
|
+
def __post_init__(self, **kwargs):
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
def __init__(self, key=None, **kwargs):
|
|
22
|
+
global element_count
|
|
23
|
+
if key is None:
|
|
24
|
+
key = str(element_count)
|
|
25
|
+
element_count += 1
|
|
26
|
+
|
|
27
|
+
self.__dict__.update(tag=self.tag, key=key, **kwargs)
|
|
28
|
+
self.__post_init__(**{k: v for k, v in kwargs.items() if k.startswith("_")})
|
|
29
|
+
|
|
30
|
+
def serialize(self):
|
|
31
|
+
"""
|
|
32
|
+
Serialize the element to a dictionary for sending over the websocket.
|
|
33
|
+
|
|
34
|
+
:return: Dictionary representing the element.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
# note: only return the non-private attributes, allow bypass.
|
|
38
|
+
output = {}
|
|
39
|
+
for k, v in self.__dict__.items():
|
|
40
|
+
if k.startswith("_"):
|
|
41
|
+
continue
|
|
42
|
+
if hasattr(v, "tolist"):
|
|
43
|
+
output[k] = v.tolist()
|
|
44
|
+
else:
|
|
45
|
+
output[k] = v
|
|
46
|
+
|
|
47
|
+
return output
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class BlockElement(Element):
|
|
51
|
+
def __init__(self, *children, **kwargs):
|
|
52
|
+
self.children = children
|
|
53
|
+
super().__init__(**kwargs)
|
|
54
|
+
|
|
55
|
+
def serialize(self):
|
|
56
|
+
# writ this as multiple lines
|
|
57
|
+
children = []
|
|
58
|
+
for e in self.children:
|
|
59
|
+
if isinstance(e, str):
|
|
60
|
+
children.append(e)
|
|
61
|
+
else:
|
|
62
|
+
children.append(e.serialize())
|
|
63
|
+
return {**super().serialize(), "children": children}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class AutoScroll(BlockElement):
|
|
67
|
+
tag = "AutoScroll"
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class Markdown(BlockElement):
|
|
71
|
+
tag = "Markdown"
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class Page(BlockElement):
|
|
75
|
+
"""
|
|
76
|
+
A Page is an element that contains other elements.
|
|
77
|
+
It is represented by a div element in the DOM.
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
tag = "article"
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class div(BlockElement):
|
|
84
|
+
tag = "Div"
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class InputBox(Element):
|
|
88
|
+
"""
|
|
89
|
+
An InputBox is an element that allows the user to input text.
|
|
90
|
+
It is represented by an input element in the DOM.
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
tag = "Input"
|
|
94
|
+
|
|
95
|
+
def __init__(self, **kwargs):
|
|
96
|
+
super().__init__(**kwargs)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class Header1(BlockElement):
|
|
100
|
+
"""
|
|
101
|
+
A Text element is an element that displays text.
|
|
102
|
+
It is represented by a text, or p element in the DOM.
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
tag = "h1"
|
|
106
|
+
|
|
107
|
+
def __init__(self, *children, **kwargs):
|
|
108
|
+
children = [Text(c) if isinstance(c, str) else c for c in children]
|
|
109
|
+
super().__init__(*children, **kwargs)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
Header = Header1
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class Header2(Header1):
|
|
116
|
+
"""Header 2"""
|
|
117
|
+
|
|
118
|
+
tag = "h2"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class Header3(Header1):
|
|
122
|
+
"""Header 2"""
|
|
123
|
+
|
|
124
|
+
tag = "h3"
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class Paragraph(BlockElement):
|
|
128
|
+
"""
|
|
129
|
+
A Text element is an element that displays text.
|
|
130
|
+
It is represented by a text, or p element in the DOM.
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
tag = "p"
|
|
134
|
+
|
|
135
|
+
def __init__(self, *children, **kwargs):
|
|
136
|
+
children = [Text(c) if isinstance(c, str) else c for c in children]
|
|
137
|
+
super().__init__(*children, **kwargs)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class Text(Element):
|
|
141
|
+
"""
|
|
142
|
+
A Text element is an element that displays text.
|
|
143
|
+
It is represented by a text, or p element in the DOM.
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
tag = "Text"
|
|
147
|
+
|
|
148
|
+
def __init__(self, *text, sep=" ", **kwargs):
|
|
149
|
+
self.text = sep.join(text)
|
|
150
|
+
super().__init__(**kwargs)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class Bold(Text):
|
|
154
|
+
def __init__(self, text, style=None, **kwargs):
|
|
155
|
+
_style = {"fontWeight": "bold"}
|
|
156
|
+
_style.update(style or {})
|
|
157
|
+
super().__init__(text, style=_style, **kwargs)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class Italic(Text):
|
|
161
|
+
def __init__(self, text, style=None, **kwargs):
|
|
162
|
+
_style = {"fontStyle": "italic"}
|
|
163
|
+
_style.update(style or {})
|
|
164
|
+
super().__init__(text, style=_style, **kwargs)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class Link(Text):
|
|
168
|
+
tag = "a"
|
|
169
|
+
|
|
170
|
+
def __init__(self, text, src, **kwargs):
|
|
171
|
+
super().__init__(text, src=src, **kwargs)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class Button(Element):
|
|
175
|
+
"""
|
|
176
|
+
A Button element is an element that allows the user to click on it.
|
|
177
|
+
It is represented by a button element in the DOM.
|
|
178
|
+
"""
|
|
179
|
+
|
|
180
|
+
tag = "Button"
|
|
181
|
+
|
|
182
|
+
def __init__(self, **kwargs):
|
|
183
|
+
super().__init__(**kwargs)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class Slider(Element):
|
|
187
|
+
"""
|
|
188
|
+
A Slider element is an element that allows the user to slide a value.
|
|
189
|
+
It is represented by a slider element in the DOM.
|
|
190
|
+
"""
|
|
191
|
+
|
|
192
|
+
tag = "Slider"
|
|
193
|
+
|
|
194
|
+
def __init__(self, **kwargs):
|
|
195
|
+
"""
|
|
196
|
+
:param min: Minimum value of the slider
|
|
197
|
+
:param max: Maximum value of the slider
|
|
198
|
+
:param step: Step size of the slider
|
|
199
|
+
:param value: Initial value of the slider
|
|
200
|
+
:param kwargs:
|
|
201
|
+
"""
|
|
202
|
+
super().__init__(**kwargs)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
class Image(Element):
|
|
206
|
+
"""
|
|
207
|
+
An Image element is an element that displays an image.
|
|
208
|
+
It is represented by an img element in the DOM.
|
|
209
|
+
"""
|
|
210
|
+
|
|
211
|
+
tag = "Img"
|
|
212
|
+
|
|
213
|
+
def __init__(
|
|
214
|
+
self,
|
|
215
|
+
data: Union[str, np.ndarray, pil_image.Image] = None,
|
|
216
|
+
*,
|
|
217
|
+
src: str = None,
|
|
218
|
+
format="png",
|
|
219
|
+
**kwargs,
|
|
220
|
+
):
|
|
221
|
+
if src is not None:
|
|
222
|
+
assert data is None, "data and src can not be truful at the same time"
|
|
223
|
+
if data is None:
|
|
224
|
+
pass
|
|
225
|
+
elif isinstance(data, list) and len(data) == 0:
|
|
226
|
+
pass
|
|
227
|
+
else:
|
|
228
|
+
if isinstance(data, pil_image.Image):
|
|
229
|
+
data = data
|
|
230
|
+
elif isinstance(data, str):
|
|
231
|
+
# convert back to image first from base64
|
|
232
|
+
data = pil_image.open(data)
|
|
233
|
+
elif isinstance(data, np.ndarray):
|
|
234
|
+
if data.dtype == np.uint8:
|
|
235
|
+
pass
|
|
236
|
+
else:
|
|
237
|
+
data = (data * 255).astype(np.uint8)
|
|
238
|
+
|
|
239
|
+
src = IMAGE_FORMATS[format](data)
|
|
240
|
+
|
|
241
|
+
super().__init__(src=src, **kwargs)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
class ImageUpload(Element):
|
|
245
|
+
"""
|
|
246
|
+
A ImageUpload element is an element that allows the user to upload a file.
|
|
247
|
+
It is represented by a file upload element in the DOM.
|
|
248
|
+
"""
|
|
249
|
+
|
|
250
|
+
tag = "ImageUpload"
|
|
251
|
+
|
|
252
|
+
def __init__(self, **kwargs):
|
|
253
|
+
super().__init__(**kwargs)
|
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from numpy._typing import NDArray
|
|
3
|
+
from typing import List
|
|
4
|
+
|
|
5
|
+
from vuer.schemas.html_components import BlockElement, Image, Element
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Scene(BlockElement):
|
|
9
|
+
tag = "Scene"
|
|
10
|
+
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
*children,
|
|
14
|
+
rawChildren=None,
|
|
15
|
+
htmlChildren=None,
|
|
16
|
+
bgChildren=None,
|
|
17
|
+
# default to y-up to be consistent with three.js. Blender uses z-up though.
|
|
18
|
+
up=[0, 1, 0],
|
|
19
|
+
**kwargs,
|
|
20
|
+
):
|
|
21
|
+
super().__init__(*children, up=up, **kwargs)
|
|
22
|
+
self.rawChildren = rawChildren or []
|
|
23
|
+
self.htmlChildren = htmlChildren or []
|
|
24
|
+
self.bgChildren = bgChildren or []
|
|
25
|
+
|
|
26
|
+
def serialize(self):
|
|
27
|
+
obj = super().serialize()
|
|
28
|
+
if self.rawChildren:
|
|
29
|
+
obj["rawChildren"] = [e.serialize() for e in self.rawChildren if e]
|
|
30
|
+
if self.htmlChildren:
|
|
31
|
+
obj["htmlChildren"] = [e.serialize() for e in self.htmlChildren if e]
|
|
32
|
+
if self.bgChildren:
|
|
33
|
+
obj["bgChildren"] = [e.serialize() for e in self.bgChildren if e]
|
|
34
|
+
return obj
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class SceneElement(BlockElement):
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class Frustum(SceneElement):
|
|
42
|
+
"""Camera Frustum
|
|
43
|
+
|
|
44
|
+
:param position: An optional tuple of three numbers representing the position.
|
|
45
|
+
:type position: tuple[float, float, float]
|
|
46
|
+
:param rotation: An optional tuple of three numbers representing the rotation.
|
|
47
|
+
:type rotation: tuple[float, float, float]
|
|
48
|
+
:param matrix: An optional tuple of sixteen numbers representing the matrix.
|
|
49
|
+
:type matrix: tuple[float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float]
|
|
50
|
+
:param aspect: An optional number representing the aspect.
|
|
51
|
+
:type aspect: float
|
|
52
|
+
:param focus: An optional number representing the focus.
|
|
53
|
+
:type focus: float
|
|
54
|
+
:param fov: An optional number representing the field of view.
|
|
55
|
+
:type fov: float
|
|
56
|
+
:param near: An optional number representing the near field.
|
|
57
|
+
:type near: float
|
|
58
|
+
:param far: An optional number representing the far field.
|
|
59
|
+
:type far: float
|
|
60
|
+
:param scale: An optional number representing the scale.
|
|
61
|
+
:type scale: float
|
|
62
|
+
:param upScale: An optional number representing the up scale.
|
|
63
|
+
:type upScale: float
|
|
64
|
+
:param focalLength: An optional number representing the focal length.
|
|
65
|
+
:type focalLength: float
|
|
66
|
+
:param showUp: An optional boolean indicating whether to show up.
|
|
67
|
+
:type showUp: bool
|
|
68
|
+
:param showFrustum: An optional boolean indicating whether to show the frustum.
|
|
69
|
+
:type showFrustum: bool
|
|
70
|
+
:param showFocalPlane: An optional boolean indicating whether to show the focal plane.
|
|
71
|
+
:type showFocalPlane: bool
|
|
72
|
+
:param showImagePlane: An optional boolean indicating whether to show the image plane.
|
|
73
|
+
:type showImagePlane: bool
|
|
74
|
+
:param src: An optional string representing the source.
|
|
75
|
+
:type src: str
|
|
76
|
+
:param colorOrigin: An optional ColorRepresentation for the origin color.
|
|
77
|
+
:type colorOrigin: ColorRepresentation
|
|
78
|
+
:param colorFrustum: An optional ColorRepresentation for the frustum color.
|
|
79
|
+
:type colorFrustum: ColorRepresentation
|
|
80
|
+
:param colorCone: An optional ColorRepresentation for the cone color.
|
|
81
|
+
:type colorCone: ColorRepresentation
|
|
82
|
+
:param colorFocalPlane: An optional ColorRepresentation for the focal plane color.
|
|
83
|
+
:type colorFocalPlane: ColorRepresentation
|
|
84
|
+
:param colorUp: An optional ColorRepresentation for the up color.
|
|
85
|
+
:type colorUp: ColorRepresentation
|
|
86
|
+
:param colorTarget: An optional ColorRepresentation for the target color.
|
|
87
|
+
:type colorTarget: ColorRepresentation
|
|
88
|
+
:param colorCross: An optional ColorRepresentation for the cross color.
|
|
89
|
+
:type colorCross: ColorRepresentation
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
tag = "Frustum"
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class CameraHelper(SceneElement):
|
|
96
|
+
tag = "CameraHelper"
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class group(SceneElement):
|
|
100
|
+
tag = "group"
|
|
101
|
+
children = []
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class mesh(SceneElement):
|
|
105
|
+
tag = "mesh"
|
|
106
|
+
children = []
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class TriMesh(SceneElement):
|
|
110
|
+
tag = "TriMesh"
|
|
111
|
+
children = []
|
|
112
|
+
|
|
113
|
+
vertices: NDArray[np.float16] = None
|
|
114
|
+
# note: Uint16 is too few. Quickly overflows
|
|
115
|
+
faces: NDArray[np.uint32] = None
|
|
116
|
+
colors: NDArray[np.uint8] = None
|
|
117
|
+
|
|
118
|
+
def __post_init__(self, **kwargs):
|
|
119
|
+
self.vertices = self.vertices.astype(np.float16).flatten().tobytes()
|
|
120
|
+
|
|
121
|
+
# uinit16 is too few at 65536. Have to use uint32.
|
|
122
|
+
self.faces = self.faces.astype(np.uint32).flatten().tobytes()
|
|
123
|
+
|
|
124
|
+
if self.colors is None:
|
|
125
|
+
return
|
|
126
|
+
|
|
127
|
+
if self.colors.shape[-1] == 4:
|
|
128
|
+
self.colors = self.colors[:, :3]
|
|
129
|
+
|
|
130
|
+
# send only integers: https://stackoverflow.com/questions/34669537
|
|
131
|
+
if self.colors.dtype != np.uint8:
|
|
132
|
+
self.colors *= 255
|
|
133
|
+
self.colors = self.colors.astype(np.uint8)
|
|
134
|
+
|
|
135
|
+
self.colors = self.colors.flatten().tobytes()
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class PointCloud(SceneElement):
|
|
139
|
+
"""PointCould element, highly optimized for payload size and speed.
|
|
140
|
+
|
|
141
|
+
:param vertices: An optional numpy array of shape (N, 3) containing the vertices of the pointcloud.
|
|
142
|
+
:type vertices: NDArray[np.float16]
|
|
143
|
+
:param colors: An optional numpy array of shape (N, 3) containing the colors of the point cloud.
|
|
144
|
+
:type color: NDArray[np.uint8]
|
|
145
|
+
:param size: An optional float that sets the size of the points.
|
|
146
|
+
:type size: float
|
|
147
|
+
:param key: str An optional string that sets the key of the element.
|
|
148
|
+
:type key: str
|
|
149
|
+
|
|
150
|
+
Usage::
|
|
151
|
+
|
|
152
|
+
sess.upsert @ PointCloud(
|
|
153
|
+
vertices=np.random.rand(1000, 3),
|
|
154
|
+
colors=np.random.rand(1000, 3),
|
|
155
|
+
size=0.01,
|
|
156
|
+
key="pointcloud",
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
"""
|
|
160
|
+
|
|
161
|
+
tag: str = "PointCloud"
|
|
162
|
+
vertices: NDArray[np.float16] = None
|
|
163
|
+
"""An optional numpy array of shape (N, 3) containing the vertices of the point cloud."""
|
|
164
|
+
colors: NDArray[np.uint8] = None
|
|
165
|
+
"""An optional numpy array of shape (N, 3) containing the colors of the point cloud."""
|
|
166
|
+
children = []
|
|
167
|
+
|
|
168
|
+
def __post_init__(self, **kwargs):
|
|
169
|
+
self.vertices = self.vertices.astype(np.float16).flatten().tobytes()
|
|
170
|
+
|
|
171
|
+
if self.colors is None:
|
|
172
|
+
return
|
|
173
|
+
|
|
174
|
+
if self.colors.shape[-1] == 4:
|
|
175
|
+
self.colors = self.colors[:, :3]
|
|
176
|
+
|
|
177
|
+
if self.colors.dtype != np.uint8:
|
|
178
|
+
# todo: use this and send only integers: https://stackoverflow.com/questions/34669537
|
|
179
|
+
self.colors *= 255
|
|
180
|
+
self.colors = self.colors.astype(np.uint8)
|
|
181
|
+
|
|
182
|
+
self.colors = self.colors.flatten().tobytes()
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
p = PointCloud
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class Box(SceneElement):
|
|
189
|
+
tag = "Box"
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class Capsule(SceneElement):
|
|
193
|
+
tag = "Capsule"
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
class Cone(SceneElement):
|
|
197
|
+
tag = "Cone"
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class Circle(SceneElement):
|
|
201
|
+
tag = "Circle"
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
class Cylinder(SceneElement):
|
|
205
|
+
tag = "Cylinder"
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class Dodecahedron(SceneElement):
|
|
209
|
+
tag = "Dodecahedron"
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class Edges(SceneElement):
|
|
213
|
+
tag = "Edges"
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
class Extrude(SceneElement):
|
|
217
|
+
tag = "Extrude"
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
class Icosahedron(SceneElement):
|
|
221
|
+
tag = "Icosahedron"
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
class Lathe(SceneElement):
|
|
225
|
+
tag = "Lathe"
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class Octahedron(SceneElement):
|
|
229
|
+
tag = "Octahedron"
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
class Plane(SceneElement):
|
|
233
|
+
tag = "Plane"
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
class Polyhedron(SceneElement):
|
|
237
|
+
tag = "Polyhedron"
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
class Ring(SceneElement):
|
|
241
|
+
tag = "Ring"
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
class Shape(SceneElement):
|
|
245
|
+
tag = "Shape"
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
class Sphere(SceneElement):
|
|
249
|
+
tag = "Sphere"
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
class Tetrahedron(SceneElement):
|
|
253
|
+
tag = "Tetrahedron"
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
class Torus(SceneElement):
|
|
257
|
+
tag = "Torus"
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
class TorusKnot(SceneElement):
|
|
261
|
+
tag = "TorusKnot"
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
class Tube(SceneElement):
|
|
265
|
+
tag = "Tube"
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
class Fog(SceneElement):
|
|
269
|
+
"""
|
|
270
|
+
Fog is a scene element that adds fog to the scene. This
|
|
271
|
+
can be used to approximate depth.
|
|
272
|
+
|
|
273
|
+
Arguments:
|
|
274
|
+
args: color, near, far
|
|
275
|
+
|
|
276
|
+
Example Usage:
|
|
277
|
+
Fog(args=[0xcccccc, 10, 15])
|
|
278
|
+
|
|
279
|
+
"""
|
|
280
|
+
|
|
281
|
+
tag = "fog"
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
class Wireframe(SceneElement):
|
|
285
|
+
tag = "Wireframe"
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
class Splat(SceneElement):
|
|
289
|
+
tag = "Splat"
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
class LumaSplats(SceneElement):
|
|
293
|
+
tag = "Splats"
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
class Pcd(SceneElement):
|
|
297
|
+
tag = "Pcd"
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
class CameraView(SceneElement):
|
|
301
|
+
tag = "CameraView"
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
class SceneBackground(Image, SceneElement):
|
|
305
|
+
"""Sets the background of the scene to a static image. Does not work well
|
|
306
|
+
with high frame rates. For displaying movies, use the ImageBackground element.
|
|
307
|
+
"""
|
|
308
|
+
|
|
309
|
+
tag = "SceneBackground"
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
class ImageBackground(Image, SceneElement):
|
|
313
|
+
"""Sets the background of the scene to an image, Supports high frame rates.
|
|
314
|
+
|
|
315
|
+
We use a plane that is always facing the camera to display the image.
|
|
316
|
+
"""
|
|
317
|
+
|
|
318
|
+
tag = "ImageBackground"
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
class Gamepads(SceneElement):
|
|
322
|
+
tag = "Gamepads"
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
class DirectionalLight(SceneElement):
|
|
326
|
+
tag = "DirectionalLight"
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
class PointLight(SceneElement):
|
|
330
|
+
tag = "PointLight"
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
class SpotLight(SceneElement):
|
|
334
|
+
tag = "SpotLight"
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
class AmbientLight(SceneElement):
|
|
338
|
+
tag = "AmbientLight"
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
class Html(SceneElement):
|
|
342
|
+
"""
|
|
343
|
+
Usage::
|
|
344
|
+
|
|
345
|
+
as='div' // Wrapping element (default: 'div')
|
|
346
|
+
wrapperClass // The className of the wrapping element (default: undefined)
|
|
347
|
+
prepend // Project content behind the canvas (default: false)
|
|
348
|
+
center // Adds a -50%/-50% css transform (default: false) [ignored in transform mode]
|
|
349
|
+
fullscreen // Aligns to the upper-left corner, fills the screen (default:false) [ignored in transform mode]
|
|
350
|
+
distanceFactor={10} // If set (default: undefined), children will be scaled by this factor, and also by distance to a PerspectiveCamera / zoom by a OrthographicCamera.
|
|
351
|
+
zIndexRange={[100, 0]} // Z-order range (default=[16777271, 0])
|
|
352
|
+
portal={domnodeRef} // Reference to target container (default=undefined)
|
|
353
|
+
transform // If true, applies matrix3d transformations (default=false)
|
|
354
|
+
sprite // Renders as sprite, but only in transform mode (default=false)
|
|
355
|
+
calculatePosition={(el: Object3D, camera: Camera, size: { width: number; height: number }) => number[]} // Override default positioning function. (default=undefined) [ignored in transform mode]
|
|
356
|
+
occlude={[ref]} // Can be true or a Ref<Object3D>[], true occludes the entire scene (default: undefined)
|
|
357
|
+
onOcclude={(visible) => null} // Callback when the visibility changes (default: undefined)
|
|
358
|
+
{...groupProps} // All THREE.Group props are valid
|
|
359
|
+
{...divProps} // All HTMLDivElement props are valid
|
|
360
|
+
|
|
361
|
+
"""
|
|
362
|
+
|
|
363
|
+
tag = "Html"
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
class Pivot(SceneElement):
|
|
367
|
+
tag = "Pivot"
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
class Movable(SceneElement):
|
|
371
|
+
tag = "Movable"
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
class Obj(SceneElement):
|
|
375
|
+
tag = "Obj"
|
|
376
|
+
|
|
377
|
+
def __init__(self, src, mtl=None, materials=None, **kwargs):
|
|
378
|
+
"""
|
|
379
|
+
:param src: The source of the obj file. Can be a url or a local file.
|
|
380
|
+
:type src: str
|
|
381
|
+
:param mtlSrc: The source of the mtl file. Can be a url or a local file.
|
|
382
|
+
:type mtlSrc: str
|
|
383
|
+
:param materials: A list of materials to be used for the obj file.
|
|
384
|
+
:type materials: List[String]
|
|
385
|
+
|
|
386
|
+
todo: In the future we probably want to enable the loading of multiple material files.
|
|
387
|
+
"""
|
|
388
|
+
self.src = src
|
|
389
|
+
self.mtl = mtl
|
|
390
|
+
self.materials = []
|
|
391
|
+
|
|
392
|
+
super().__init__(**kwargs)
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
class CoordsMarker(SceneElement):
|
|
396
|
+
tag = "CoordsMarker"
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
class Ply(SceneElement):
|
|
400
|
+
tag = "Ply"
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
class Glb(SceneElement):
|
|
404
|
+
tag = "Glb"
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
class Urdf(SceneElement):
|
|
408
|
+
tag = "Urdf"
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
class Gripper(SceneElement):
|
|
412
|
+
tag = "Gripper"
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
class SkeletalGripper(SceneElement):
|
|
416
|
+
tag = "SkeletalGripper"
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
class Grid(SceneElement):
|
|
420
|
+
tag = "Grid"
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
class GrabRender(SceneElement):
|
|
424
|
+
tag = "GrabRender"
|
|
425
|
+
key = "DEFAULT"
|
|
426
|
+
"""We do not want the client to set keys automatically since GrabRender is
|
|
427
|
+
usually used a singleton component as default."""
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
class TimelineControls(SceneElement):
|
|
431
|
+
tag = "TimelineControls"
|
|
432
|
+
# todo: consider adding default component keys here.
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
class PointerControls(SceneElement):
|
|
436
|
+
tag = "PointerControls"
|
|
437
|
+
# todo: consider adding default component keys here.
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
class DefaultScene(Scene):
|
|
441
|
+
"""Default Scene that includes a basic setup of ambient lights.
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
:param children: list of children elements to be rendered in the scene.
|
|
445
|
+
:type children: SceneElement, ...
|
|
446
|
+
:param rawChildren: list of children elements to be rendered in the scene.
|
|
447
|
+
:param htmlChildren: list of children elements to be rendered in the scene.
|
|
448
|
+
:param bgChildren: list of children elements to be rendered in the scene.
|
|
449
|
+
:param show_helper: list of children elements to be rendered in the scene.
|
|
450
|
+
:param startStep: list of children elements to be rendered in the scene.
|
|
451
|
+
:param endStep: list of children elements to be rendered in the scene.
|
|
452
|
+
:param up: list of children elements to be rendered in the scene.
|
|
453
|
+
:param kwargs: list of children elements to be rendered in the scene.
|
|
454
|
+
|
|
455
|
+
Example Usage::
|
|
456
|
+
|
|
457
|
+
DefaultScene(
|
|
458
|
+
# Ambient Light does not have helper because it is ambient.
|
|
459
|
+
AmbientLight(intensity=1.0, key="default_ambient_light"),
|
|
460
|
+
DirectionalLight(
|
|
461
|
+
intensity=1, key="default_directional_light", helper=show_helper
|
|
462
|
+
),
|
|
463
|
+
*children,
|
|
464
|
+
rawChildren=rawChildren,
|
|
465
|
+
htmlChildren=htmlChildren,
|
|
466
|
+
bgChildren=[
|
|
467
|
+
GrabRender(),
|
|
468
|
+
*[
|
|
469
|
+
# we use a key here so that we can replace the timeline controls via update
|
|
470
|
+
TimelineControls(start=startStep, end=endStep, key="timeline")
|
|
471
|
+
if endStep
|
|
472
|
+
else None,
|
|
473
|
+
],
|
|
474
|
+
PointerControls(),
|
|
475
|
+
Grid(),
|
|
476
|
+
*bgChildren,
|
|
477
|
+
],
|
|
478
|
+
up=up,
|
|
479
|
+
**kwargs,
|
|
480
|
+
)
|
|
481
|
+
"""
|
|
482
|
+
|
|
483
|
+
def __init__(
|
|
484
|
+
self,
|
|
485
|
+
*children: SceneElement,
|
|
486
|
+
rawChildren: List[SceneElement] = None,
|
|
487
|
+
htmlChildren: List[Element] = None,
|
|
488
|
+
bgChildren: List[SceneElement] = [],
|
|
489
|
+
show_helper=True,
|
|
490
|
+
startStep=0,
|
|
491
|
+
endStep=None,
|
|
492
|
+
# default to z-up
|
|
493
|
+
up=[0, 0, 1],
|
|
494
|
+
**kwargs,
|
|
495
|
+
):
|
|
496
|
+
rawChildren = [
|
|
497
|
+
AmbientLight(intensity=1.0, key="default_ambient_light"),
|
|
498
|
+
DirectionalLight(intensity=1, key="default_directional_light", helper=show_helper),
|
|
499
|
+
*(rawChildren or []),
|
|
500
|
+
]
|
|
501
|
+
|
|
502
|
+
super().__init__(
|
|
503
|
+
# Ambient Light does not have helper because it is ambient.
|
|
504
|
+
*children,
|
|
505
|
+
rawChildren=rawChildren,
|
|
506
|
+
htmlChildren=htmlChildren,
|
|
507
|
+
bgChildren=[
|
|
508
|
+
# skey spec here is a little redundant.
|
|
509
|
+
GrabRender(key="DEFAULT"),
|
|
510
|
+
*[
|
|
511
|
+
# we use a key here so that we can replace the timeline controls via update
|
|
512
|
+
TimelineControls(start=startStep, end=endStep, key="timeline")
|
|
513
|
+
if endStep
|
|
514
|
+
else None,
|
|
515
|
+
],
|
|
516
|
+
PointerControls(),
|
|
517
|
+
Grid(),
|
|
518
|
+
*bgChildren,
|
|
519
|
+
],
|
|
520
|
+
up=up,
|
|
521
|
+
**kwargs,
|
|
522
|
+
)
|
vuer/server.py
CHANGED
|
@@ -27,7 +27,7 @@ from vuer.events import (
|
|
|
27
27
|
Upsert,
|
|
28
28
|
)
|
|
29
29
|
from vuer.schemas import Page
|
|
30
|
-
from vuer.types import EventHandler,
|
|
30
|
+
from vuer.types import EventHandler, SocketHandler
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
class At:
|
|
@@ -228,8 +228,36 @@ class VuerSession:
|
|
|
228
228
|
|
|
229
229
|
|
|
230
230
|
class Vuer(PrefixProto, Server):
|
|
231
|
-
"""
|
|
232
|
-
|
|
231
|
+
"""Vuer Server
|
|
232
|
+
|
|
233
|
+
This is the server for the Vuer client.
|
|
234
|
+
|
|
235
|
+
Usage::
|
|
236
|
+
|
|
237
|
+
app = Vuer()
|
|
238
|
+
|
|
239
|
+
@app.spawn
|
|
240
|
+
async def main(session: VuerSession):
|
|
241
|
+
session.set @ Scene(children=[...])
|
|
242
|
+
|
|
243
|
+
app.run()
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
.. automethod:: bind
|
|
247
|
+
.. automethod:: spawn
|
|
248
|
+
.. automethod:: relay
|
|
249
|
+
.. automethod:: bound_fn
|
|
250
|
+
.. automethod:: spawn_task
|
|
251
|
+
.. automethod:: get_url
|
|
252
|
+
.. automethod:: send
|
|
253
|
+
.. automethod:: rpc
|
|
254
|
+
.. automethod:: rpc_stream
|
|
255
|
+
.. automethod:: close_ws
|
|
256
|
+
.. automethod:: uplink
|
|
257
|
+
.. automethod:: downlink
|
|
258
|
+
.. automethod:: add_handler
|
|
259
|
+
.. automethod:: _ttl_handler
|
|
260
|
+
.. automethod:: run
|
|
233
261
|
"""
|
|
234
262
|
|
|
235
263
|
name = "vuer"
|
|
@@ -239,14 +267,12 @@ class Vuer(PrefixProto, Server):
|
|
|
239
267
|
port = 8012
|
|
240
268
|
free_port = True
|
|
241
269
|
static_root = "."
|
|
242
|
-
queue_len = 100 # use a max
|
|
270
|
+
queue_len = 100 # use a max length to avoid the memory from blowing up.
|
|
243
271
|
cors = "https://vuer.ai,https://dash.ml,http://localhost:8000,http://127.0.0.1:8000,*"
|
|
244
272
|
queries = Proto({}, help="query parameters to pass")
|
|
245
273
|
|
|
246
274
|
device = "cuda"
|
|
247
275
|
|
|
248
|
-
# need to be awaited
|
|
249
|
-
|
|
250
276
|
def _proxy(self, ws_id) -> "VuerSession":
|
|
251
277
|
"""This is a proxy object that allows us to use the @ notation
|
|
252
278
|
to send events to the client.
|
|
@@ -269,7 +295,7 @@ class Vuer(PrefixProto, Server):
|
|
|
269
295
|
self.page = Page()
|
|
270
296
|
|
|
271
297
|
self.ws = {}
|
|
272
|
-
self.
|
|
298
|
+
self.socket_handler: SocketHandler = None
|
|
273
299
|
self.spawned_coroutines = []
|
|
274
300
|
|
|
275
301
|
async def relay(self, request):
|
|
@@ -280,11 +306,11 @@ class Vuer(PrefixProto, Server):
|
|
|
280
306
|
|
|
281
307
|
Interface:
|
|
282
308
|
<uri>/relay?sid=<websocket_id>
|
|
309
|
+
|
|
283
310
|
:return:
|
|
284
311
|
- Status 200
|
|
285
312
|
- Status 400
|
|
286
313
|
|
|
287
|
-
|
|
288
314
|
"""
|
|
289
315
|
# todo: need to implement msgpack encoding, interface
|
|
290
316
|
bytes = request.bytes()
|
|
@@ -340,20 +366,18 @@ class Vuer(PrefixProto, Server):
|
|
|
340
366
|
loop = asyncio.get_running_loop()
|
|
341
367
|
return loop.create_task(task)
|
|
342
368
|
|
|
343
|
-
def spawn(self, fn:
|
|
369
|
+
def spawn(self, fn: SocketHandler = None, start=False):
|
|
344
370
|
"""
|
|
345
|
-
Spawn a function as a task. This is useful in the following scenario:
|
|
346
|
-
|
|
347
|
-
code::
|
|
348
371
|
|
|
372
|
+
Note: this is really a misnomer.
|
|
349
373
|
|
|
350
374
|
:param fn: The function to spawn.
|
|
351
375
|
:param start: Start server after binding
|
|
352
376
|
:return: None
|
|
353
377
|
"""
|
|
354
378
|
|
|
355
|
-
def wrap_fn(fn:
|
|
356
|
-
self.
|
|
379
|
+
def wrap_fn(fn: SocketHandler):
|
|
380
|
+
self.socket_handler = fn
|
|
357
381
|
if start:
|
|
358
382
|
self.run()
|
|
359
383
|
|
|
@@ -365,7 +389,7 @@ class Vuer(PrefixProto, Server):
|
|
|
365
389
|
|
|
366
390
|
def bind(self, fn=None, start=False):
|
|
367
391
|
"""
|
|
368
|
-
Bind
|
|
392
|
+
Bind an asynchronous generator function for use in socket connection handler. The function should be a generator that yields Page objects.
|
|
369
393
|
|
|
370
394
|
:param fn: The function to bind.
|
|
371
395
|
:return: None
|
|
@@ -505,8 +529,8 @@ class Vuer(PrefixProto, Server):
|
|
|
505
529
|
|
|
506
530
|
self._add_task(self.uplink(vuer_proxy))
|
|
507
531
|
|
|
508
|
-
if self.
|
|
509
|
-
task = self._add_task(self.
|
|
532
|
+
if self.socket_handler is not None:
|
|
533
|
+
task = self._add_task(self.socket_handler(vuer_proxy))
|
|
510
534
|
|
|
511
535
|
if hasattr(generator, "__anext__"):
|
|
512
536
|
serverEvent = await generator.__anext__()
|
|
@@ -554,7 +578,7 @@ class Vuer(PrefixProto, Server):
|
|
|
554
578
|
def add_handler(
|
|
555
579
|
self,
|
|
556
580
|
event_type: str,
|
|
557
|
-
fn: EventHandler,
|
|
581
|
+
fn: EventHandler = None,
|
|
558
582
|
once: bool = False,
|
|
559
583
|
) -> Callable[[], None]:
|
|
560
584
|
"""Adding event handlers to the vuer server.
|
|
@@ -565,7 +589,29 @@ class Vuer(PrefixProto, Server):
|
|
|
565
589
|
This is useful for RPC, which cleans up after itself.
|
|
566
590
|
The issue is for RPC, the `key` also needs to match. So we hack it here to use
|
|
567
591
|
a call specific event_type to enforce the cleanup.
|
|
592
|
+
|
|
593
|
+
# Usage:
|
|
594
|
+
|
|
595
|
+
As a decorator::
|
|
596
|
+
|
|
597
|
+
app = Vuer()
|
|
598
|
+
@app.add_handler("CAMERA_MOVE")
|
|
599
|
+
def on_camera(event: ClientEvent, session: VuerSession):
|
|
600
|
+
print("camera event", event.etype, event.value)
|
|
601
|
+
|
|
602
|
+
As a function::
|
|
603
|
+
|
|
604
|
+
app = Vuer()
|
|
605
|
+
def on_camera(event: ClientEvent, session: VuerSession):
|
|
606
|
+
print("camera event", event.etype, event.value)
|
|
607
|
+
|
|
608
|
+
app.add_handler("CAMERA_MOVE", on_camera)
|
|
609
|
+
app.run()
|
|
568
610
|
"""
|
|
611
|
+
|
|
612
|
+
if fn is None:
|
|
613
|
+
return lambda fn: self.add_handler(event_type, fn, once=once)
|
|
614
|
+
|
|
569
615
|
handler_id = uuid4()
|
|
570
616
|
|
|
571
617
|
def cleanup():
|
vuer/types.py
CHANGED
|
@@ -1,11 +1,29 @@
|
|
|
1
|
-
from collections import namedtuple
|
|
2
1
|
from typing import NamedTuple, Callable, Union, Coroutine
|
|
3
2
|
from math import pi
|
|
3
|
+
from typing import NamedTuple, Callable, Union, Coroutine
|
|
4
4
|
from uuid import UUID
|
|
5
5
|
|
|
6
|
-
from vuer.events import
|
|
6
|
+
from vuer.events import ClientEvent
|
|
7
|
+
|
|
8
|
+
IDType = Union[UUID, str]
|
|
9
|
+
"""IDType is either a UUID or a string. Not in use."""
|
|
10
|
+
|
|
11
|
+
CoroutineFn = Callable[[], Coroutine]
|
|
12
|
+
"""A function that returns a coroutine. Not in use."""
|
|
13
|
+
|
|
14
|
+
# SendProxy = Callable[[ServerEvent], None]
|
|
15
|
+
EventHandler = Callable[[ClientEvent, "VuerProxy"], None]
|
|
16
|
+
"""Defines a function that handles a client event. Second argument is the VuerProxy instance bound
|
|
17
|
+
to a specific client connected through a websocket session."""
|
|
18
|
+
|
|
19
|
+
SocketHandler = Callable[["VuerProxy"], Coroutine]
|
|
20
|
+
"""Defines a function that spawns a new entity. Argument is the VuerProxy instance."""
|
|
7
21
|
|
|
8
|
-
|
|
22
|
+
|
|
23
|
+
class Vector3(NamedTuple):
|
|
24
|
+
x: int
|
|
25
|
+
y: int
|
|
26
|
+
z: int
|
|
9
27
|
|
|
10
28
|
|
|
11
29
|
class Euler(NamedTuple):
|
|
@@ -13,7 +31,6 @@ class Euler(NamedTuple):
|
|
|
13
31
|
y: int
|
|
14
32
|
z: int
|
|
15
33
|
order: str = "XYZ"
|
|
16
|
-
# unit: str = "rad"
|
|
17
34
|
|
|
18
35
|
|
|
19
36
|
class EulerDeg(Euler):
|
|
@@ -23,27 +40,12 @@ class EulerDeg(Euler):
|
|
|
23
40
|
return Euler(*[v / 180 * pi for v in self[:3]], order=self.order)
|
|
24
41
|
|
|
25
42
|
|
|
26
|
-
# class EulerRad(Euler):
|
|
27
|
-
# unit: str = "rad"
|
|
28
|
-
|
|
29
|
-
|
|
30
43
|
class Body(NamedTuple):
|
|
31
44
|
position: Vector3
|
|
32
45
|
rotation: Euler
|
|
33
46
|
scale: float
|
|
34
47
|
|
|
35
48
|
|
|
36
|
-
class RenderNode:
|
|
37
|
-
pass
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
IDType = Union[UUID, str]
|
|
41
|
-
CoroutineFn = Callable[[], Coroutine]
|
|
42
|
-
|
|
43
|
-
# SendProxy = Callable[[ServerEvent], None]
|
|
44
|
-
EventHandler = Callable[[ClientEvent, "VuerProxy"], None]
|
|
45
|
-
Spawnable = Callable[["VuerProxy"], Coroutine]
|
|
46
|
-
|
|
47
49
|
if __name__ == "__main__":
|
|
48
50
|
e = Euler(x=1, y=2, z=3)
|
|
49
51
|
assert e[:3] == (1, 2, 3)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
vuer/__init__.py,sha256=HMgKfbQAW77ukrMOnE2oKNOYbSNEkBwElpkWxLofvP8,41
|
|
2
|
+
vuer/base.py,sha256=R-PtD39ouihiEGmSfJL26chlU0XkFJP-JmBNYzDdEvM,3068
|
|
3
|
+
vuer/events.py,sha256=8AAzkfbm5jHkeMh17Z57n8YTxF4mheWC3Qbya4XkQSc,7291
|
|
4
|
+
vuer/schemas.py,sha256=aZOocE02gO43SLLfeYSxxac0x38TmyTcfs_iFh5hsJ4,18152
|
|
5
|
+
vuer/serdes.py,sha256=gD2iA9Yypu1QjocneOT3Nc0y6q_mdHn9zW1ko5j3I7c,2600
|
|
6
|
+
vuer/server.py,sha256=OsXSq6iScFTG-yvAXWAik-EwNwEKdd1F84nUqBwyrjE,19955
|
|
7
|
+
vuer/types.py,sha256=N2KLa0fl6z8Jm6cJwZoD8Vqrins_AayG5BCGk1p3Eek,1279
|
|
8
|
+
vuer/__pycache__/__init__.cpython-38.pyc,sha256=rS-9zzAjFEXnObk5q3E5Rex_uvoJ-Ccfz7Hs9DGNVgs,188
|
|
9
|
+
vuer/__pycache__/base.cpython-38.pyc,sha256=Z5EFlRX9RqZsQUszvqPtAhLv_5QG5wlUXW7JbFd_XDc,3824
|
|
10
|
+
vuer/__pycache__/events.cpython-38.pyc,sha256=zx3bXeJixqOyCFe2nA7qpq6jiCJ49kRaXO-xONGUyeQ,9616
|
|
11
|
+
vuer/__pycache__/schemas.cpython-38.pyc,sha256=hvY9Aak8zE-zKcWiwuNe6DghOw9qH_zSe_FtkBOAPPk,23234
|
|
12
|
+
vuer/__pycache__/serdes.cpython-38.pyc,sha256=KMxTjPEWuSGn2bqBAl5OLIDSCSoqfPDGfk3fvNnRDYA,2253
|
|
13
|
+
vuer/__pycache__/server.cpython-38.pyc,sha256=kAsC8t-JgTOOccZMaXZMEqgTSV3C3T5Oyj1sl-QABM4,18696
|
|
14
|
+
vuer/__pycache__/types.cpython-38.pyc,sha256=IhlXtkT-XWM0V1420FDuoqIYnpvRvekYVkGqEK7fAV8,1819
|
|
15
|
+
vuer/addons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
+
vuer/addons/nerf_vuer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
+
vuer/addons/nerf_vuer/control_components.py,sha256=K4PU0nD572L4J7lLFfShWficWZQnH4t-x6WWMrAVw8g,290
|
|
18
|
+
vuer/addons/nerf_vuer/mixins.py,sha256=fQuW3adf6X2xw_PSfS145TNfbQ9OoTKuv8mYEo6Pt6A,12966
|
|
19
|
+
vuer/addons/nerf_vuer/nerf_vuer.py,sha256=R5vI7g_sObbW1LTZ2VnR7pci7aO8iUtkKIbNnbqHnRU,5183
|
|
20
|
+
vuer/addons/nerf_vuer/render_components.py,sha256=XilHnJySJWVgmdUbPFNYyc_YWV8O5AcKkBEZOUFbnMI,3821
|
|
21
|
+
vuer/addons/nerf_vuer/render_nodes.py,sha256=5TKqIbMPiOtBxfF4FQI6uB0w_9FTfGiwS8xRbhPa0_g,14441
|
|
22
|
+
vuer/addons/nerfuer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
|
+
vuer/addons/nerfuer/render_nodes.py,sha256=EJK5N3xne5n7abTaAoLPX7SRqQ_tEen9zNypvSnZTTw,4465
|
|
24
|
+
vuer/schemas/__init__.py,sha256=ZI6UyeLZXqJbHmp6LiE3Q3mHvt1zeV-SJmmcqq-wBZE,94
|
|
25
|
+
vuer/schemas/drei_components.py,sha256=U9svEOnNprhZaobLagaFnqEtZxo5hiriSqjDnvQutoA,6989
|
|
26
|
+
vuer/schemas/html_components.py,sha256=NCqmSPic-ExPrXqNPXbKjtTXMB8sGBywIpE6cXpiy08,5926
|
|
27
|
+
vuer/schemas/scene_components.py,sha256=L9GbgFnrhxUYKi4EyexaAun7gmn6aHnCQIeSGSGwIRU,14913
|
|
28
|
+
vuer/schemas/__pycache__/__init__.cpython-38.pyc,sha256=NRnVrpIDBKne93xOUY1-WpavCG7vwYiqU3VDTEEwuUE,221
|
|
29
|
+
vuer/schemas/__pycache__/drei_components.cpython-38.pyc,sha256=g_ufcKxf-XKfZLdUV-HqKnjIrgxGWFv51aHLWQgH-ws,7712
|
|
30
|
+
vuer/schemas/__pycache__/html_components.cpython-38.pyc,sha256=q0DMFwNkYbnaH1A8w3BowMiQAlmGpFWOOKsjLVE6CIk,8215
|
|
31
|
+
vuer/schemas/__pycache__/scene_components.cpython-38.pyc,sha256=eRxB-Tp24yqBR4zbLMGX_4o1P_D-tW1nrDeBPSJKoU4,18135
|
|
32
|
+
vuer-0.0.18.dist-info/LICENSE,sha256=MGF-inVBUaGe2mEjqT0g6XsHIXwoNXgNHqD7Z1MzR0k,1063
|
|
33
|
+
vuer-0.0.18.dist-info/METADATA,sha256=cbpGK1fH2Wx_FmSLe_X9M59Dk0E_V-7v5FCS-KRfvx0,4277
|
|
34
|
+
vuer-0.0.18.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
|
35
|
+
vuer-0.0.18.dist-info/entry_points.txt,sha256=J_NM6fbpipmD9oP7cdxd1UyBR8mVEQVx0xjlE_56yss,41
|
|
36
|
+
vuer-0.0.18.dist-info/top_level.txt,sha256=ermmVkwvGFAK4gfSgDIwOmKpxwpqNt-oo7gVQQUSHok,5
|
|
37
|
+
vuer-0.0.18.dist-info/RECORD,,
|
vuer-0.0.16.dist-info/RECORD
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
vuer/__init__.py,sha256=HMgKfbQAW77ukrMOnE2oKNOYbSNEkBwElpkWxLofvP8,41
|
|
2
|
-
vuer/base.py,sha256=R-PtD39ouihiEGmSfJL26chlU0XkFJP-JmBNYzDdEvM,3068
|
|
3
|
-
vuer/events.py,sha256=2N6B9sYkxxVv6BhegBq-dIc8mxb3A42lgJz-pD1MCRU,7272
|
|
4
|
-
vuer/schemas.py,sha256=aZOocE02gO43SLLfeYSxxac0x38TmyTcfs_iFh5hsJ4,18152
|
|
5
|
-
vuer/serdes.py,sha256=gD2iA9Yypu1QjocneOT3Nc0y6q_mdHn9zW1ko5j3I7c,2600
|
|
6
|
-
vuer/server.py,sha256=YsLywahKIO75lgp4ZBuWkuQ-rxFURbVQiPYQDHluzG0,18752
|
|
7
|
-
vuer/types.py,sha256=YpRQrBzB2uGM1Lhu8eSaBGB88IgSnY4Czl5cgthxGkM,1003
|
|
8
|
-
vuer/__pycache__/__init__.cpython-38.pyc,sha256=rS-9zzAjFEXnObk5q3E5Rex_uvoJ-Ccfz7Hs9DGNVgs,188
|
|
9
|
-
vuer/__pycache__/base.cpython-38.pyc,sha256=Z5EFlRX9RqZsQUszvqPtAhLv_5QG5wlUXW7JbFd_XDc,3824
|
|
10
|
-
vuer/__pycache__/events.cpython-38.pyc,sha256=d8eqZPmim4QsTts1dkNmWmjcV4jbULFB3VjjqcHOtxo,9612
|
|
11
|
-
vuer/__pycache__/schemas.cpython-38.pyc,sha256=hvY9Aak8zE-zKcWiwuNe6DghOw9qH_zSe_FtkBOAPPk,23234
|
|
12
|
-
vuer/__pycache__/serdes.cpython-38.pyc,sha256=KMxTjPEWuSGn2bqBAl5OLIDSCSoqfPDGfk3fvNnRDYA,2253
|
|
13
|
-
vuer/__pycache__/server.cpython-38.pyc,sha256=HHbFWxrJL-cbHD2JNoRBiU2B7SJFec8PYb5qFPZupVQ,17416
|
|
14
|
-
vuer/__pycache__/types.cpython-38.pyc,sha256=eM6bZ35nB-AYALbZXf9goHjLoHxllqbIwHloi0yCOeA,1868
|
|
15
|
-
vuer/addons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
-
vuer/addons/nerf_vuer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
-
vuer/addons/nerf_vuer/control_components.py,sha256=K4PU0nD572L4J7lLFfShWficWZQnH4t-x6WWMrAVw8g,290
|
|
18
|
-
vuer/addons/nerf_vuer/mixins.py,sha256=fQuW3adf6X2xw_PSfS145TNfbQ9OoTKuv8mYEo6Pt6A,12966
|
|
19
|
-
vuer/addons/nerf_vuer/nerf_vuer.py,sha256=R5vI7g_sObbW1LTZ2VnR7pci7aO8iUtkKIbNnbqHnRU,5183
|
|
20
|
-
vuer/addons/nerf_vuer/render_components.py,sha256=XilHnJySJWVgmdUbPFNYyc_YWV8O5AcKkBEZOUFbnMI,3821
|
|
21
|
-
vuer/addons/nerf_vuer/render_nodes.py,sha256=5TKqIbMPiOtBxfF4FQI6uB0w_9FTfGiwS8xRbhPa0_g,14441
|
|
22
|
-
vuer/addons/nerfuer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
|
-
vuer/addons/nerfuer/render_nodes.py,sha256=EJK5N3xne5n7abTaAoLPX7SRqQ_tEen9zNypvSnZTTw,4465
|
|
24
|
-
vuer-0.0.16.dist-info/LICENSE,sha256=MGF-inVBUaGe2mEjqT0g6XsHIXwoNXgNHqD7Z1MzR0k,1063
|
|
25
|
-
vuer-0.0.16.dist-info/METADATA,sha256=629n5RfSb8ZXofvd-3McLXSjN9CQItqoK7Q8I7byInY,4277
|
|
26
|
-
vuer-0.0.16.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
|
27
|
-
vuer-0.0.16.dist-info/entry_points.txt,sha256=J_NM6fbpipmD9oP7cdxd1UyBR8mVEQVx0xjlE_56yss,41
|
|
28
|
-
vuer-0.0.16.dist-info/top_level.txt,sha256=ermmVkwvGFAK4gfSgDIwOmKpxwpqNt-oo7gVQQUSHok,5
|
|
29
|
-
vuer-0.0.16.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|