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.

Binary file
Binary file
Binary file
vuer/events.py CHANGED
@@ -1,7 +1,8 @@
1
- from typing import List, Type
1
+ from typing import List, Tuple
2
2
  from uuid import uuid4
3
3
 
4
- from vuer.schemas import Element, Scene
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: List[Element], strict=False):
128
+ def __init__(self, *elements: Element, strict=False):
128
129
  # tuple is not serializable
129
130
  super().__init__({"nodes": elements}, strict=strict)
130
131
 
@@ -0,0 +1,3 @@
1
+ from .html_components import *
2
+ from .scene_components import *
3
+ from .drei_components import *
@@ -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, Spawnable
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
- A Vuer is a document that can be rendered in a browser.
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 lenth to avoid the momor from blowing up.
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.spawned_fn: Spawnable = None
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: Spawnable = None, start=False):
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: Spawnable):
356
- self.spawned_fn = fn
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 a function to the Tassa. The function should be a generator that yields Page objects.
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.spawned_fn is not None:
509
- task = self._add_task(self.spawned_fn(vuer_proxy))
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 Event, ServerEvent, ClientEvent
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
- Vector3 = namedtuple("Vector3", ["x", "y", "z"])
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)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vuer
3
- Version: 0.0.16
3
+ Version: 0.0.18
4
4
  Home-page: https://github.com/geyang/vuer
5
5
  Author: Ge Yang<ge.ike.yang@gmail.com>
6
6
  Author-email: ge.ike.yang@gmail.com
@@ -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,,
@@ -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