simview 3.2__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.
- simview/__init__.py +69 -0
- simview/__main__.py +174 -0
- simview/launcher.py +109 -0
- simview/live.py +204 -0
- simview/merge.py +593 -0
- simview/model.py +690 -0
- simview/py.typed +0 -0
- simview/scene.py +603 -0
- simview/server.py +739 -0
- simview/state.py +190 -0
- simview/static/css/controls.css +36 -0
- simview/static/js/SimView.js +601 -0
- simview/static/js/components/AnimationController.js +654 -0
- simview/static/js/components/BatchManager.js +198 -0
- simview/static/js/components/InteractionController.js +446 -0
- simview/static/js/components/InteractionControls.js +116 -0
- simview/static/js/components/Scene.js +166 -0
- simview/static/js/components/StateStore.js +188 -0
- simview/static/js/config.js +233 -0
- simview/static/js/main.js +3 -0
- simview/static/js/objects/Body.js +616 -0
- simview/static/js/objects/StaticObject.js +181 -0
- simview/static/js/objects/Terrain.js +514 -0
- simview/static/js/objects/utils.js +378 -0
- simview/static/js/ui/AnalysisPanel.js +233 -0
- simview/static/js/ui/BatchLegend.js +207 -0
- simview/static/js/ui/BodyStateWindow.js +521 -0
- simview/static/js/ui/Controls.js +586 -0
- simview/static/js/ui/ErrorMetrics.js +664 -0
- simview/static/js/ui/Legend.js +87 -0
- simview/static/js/ui/PlaybackControls.js +314 -0
- simview/static/js/ui/ScalarPlotter.js +575 -0
- simview/static/js/utils/blobCodec.js +73 -0
- simview/static/js/utils/bodyTransforms.js +151 -0
- simview/static/js/utils/csv.js +46 -0
- simview/static/js/utils/errorMath.js +69 -0
- simview/static/js/utils/injectStyles.js +16 -0
- simview/static/js/utils/interpolate.js +65 -0
- simview/static/js/utils/liveFollow.js +17 -0
- simview/static/js/utils/loadRecordingLibs.js +34 -0
- simview/static/js/utils/viewState.js +226 -0
- simview/static/lib/chroma-js-3.1.2/index.min.js +8 -0
- simview/static/lib/chroma-js-3.1.2/src/Color.js +49 -0
- simview/static/lib/chroma-js-3.1.2/src/chroma.js +10 -0
- simview/static/lib/chroma-js-3.1.2/src/colors/colorbrewer.js +81 -0
- simview/static/lib/chroma-js-3.1.2/src/colors/w3cx11.js +164 -0
- simview/static/lib/chroma-js-3.1.2/src/generator/average.js +88 -0
- simview/static/lib/chroma-js-3.1.2/src/generator/bezier.js +86 -0
- simview/static/lib/chroma-js-3.1.2/src/generator/blend.js +57 -0
- simview/static/lib/chroma-js-3.1.2/src/generator/cubehelix.js +87 -0
- simview/static/lib/chroma-js-3.1.2/src/generator/mix.js +19 -0
- simview/static/lib/chroma-js-3.1.2/src/generator/random.js +12 -0
- simview/static/lib/chroma-js-3.1.2/src/generator/scale.js +394 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/_hsx.js +59 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/hcg.js +12 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/hsi.js +12 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/hsl.js +12 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/hsv.js +12 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/index.js +1 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/lab.js +19 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/lch.js +13 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/lrgb.js +19 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/num.js +15 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/oklab.js +19 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/oklch.js +12 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/rgb.js +18 -0
- simview/static/lib/chroma-js-3.1.2/src/io/cmyk/cmyk2rgb.js +16 -0
- simview/static/lib/chroma-js-3.1.2/src/io/cmyk/index.js +27 -0
- simview/static/lib/chroma-js-3.1.2/src/io/cmyk/rgb2cmyk.js +17 -0
- simview/static/lib/chroma-js-3.1.2/src/io/css/css2rgb.js +238 -0
- simview/static/lib/chroma-js-3.1.2/src/io/css/hsl2css.js +26 -0
- simview/static/lib/chroma-js-3.1.2/src/io/css/index.js +27 -0
- simview/static/lib/chroma-js-3.1.2/src/io/css/lab2css.js +24 -0
- simview/static/lib/chroma-js-3.1.2/src/io/css/lch2css.js +24 -0
- simview/static/lib/chroma-js-3.1.2/src/io/css/oklab2css.js +16 -0
- simview/static/lib/chroma-js-3.1.2/src/io/css/oklch2css.js +16 -0
- simview/static/lib/chroma-js-3.1.2/src/io/css/rgb2css.js +61 -0
- simview/static/lib/chroma-js-3.1.2/src/io/gl/index.js +22 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hcg/hcg2rgb.js +55 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hcg/index.js +27 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hcg/rgb2hcg.js +23 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hex/hex2rgb.js +56 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hex/index.js +29 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hex/rgb2hex.js +29 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hsi/hsi2rgb.js +45 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hsi/index.js +27 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hsi/rgb2hsi.js +31 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hsl/hsl2rgb.js +35 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hsl/index.js +27 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hsl/rgb2hsl.js +45 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hsv/hsv2rgb.js +47 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hsv/index.js +27 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hsv/rgb2hsv.js +32 -0
- simview/static/lib/chroma-js-3.1.2/src/io/input.js +4 -0
- simview/static/lib/chroma-js-3.1.2/src/io/lab/index.js +28 -0
- simview/static/lib/chroma-js-3.1.2/src/io/lab/lab-constants.js +120 -0
- simview/static/lib/chroma-js-3.1.2/src/io/lab/lab2rgb.js +101 -0
- simview/static/lib/chroma-js-3.1.2/src/io/lab/rgb2lab.js +67 -0
- simview/static/lib/chroma-js-3.1.2/src/io/lch/hcl2rgb.js +9 -0
- simview/static/lib/chroma-js-3.1.2/src/io/lch/index.js +35 -0
- simview/static/lib/chroma-js-3.1.2/src/io/lch/lab2lch.js +12 -0
- simview/static/lib/chroma-js-3.1.2/src/io/lch/lch2lab.js +18 -0
- simview/static/lib/chroma-js-3.1.2/src/io/lch/lch2rgb.js +13 -0
- simview/static/lib/chroma-js-3.1.2/src/io/lch/rgb2lch.js +12 -0
- simview/static/lib/chroma-js-3.1.2/src/io/named/index.js +30 -0
- simview/static/lib/chroma-js-3.1.2/src/io/num/index.js +32 -0
- simview/static/lib/chroma-js-3.1.2/src/io/num/num2rgb.js +13 -0
- simview/static/lib/chroma-js-3.1.2/src/io/num/rgb2num.js +8 -0
- simview/static/lib/chroma-js-3.1.2/src/io/oklab/index.js +27 -0
- simview/static/lib/chroma-js-3.1.2/src/io/oklab/oklab2rgb.js +34 -0
- simview/static/lib/chroma-js-3.1.2/src/io/oklab/rgb2oklab.js +37 -0
- simview/static/lib/chroma-js-3.1.2/src/io/oklch/index.js +27 -0
- simview/static/lib/chroma-js-3.1.2/src/io/oklch/oklch2rgb.js +13 -0
- simview/static/lib/chroma-js-3.1.2/src/io/oklch/rgb2oklch.js +12 -0
- simview/static/lib/chroma-js-3.1.2/src/io/rgb/index.js +44 -0
- simview/static/lib/chroma-js-3.1.2/src/io/temp/index.js +22 -0
- simview/static/lib/chroma-js-3.1.2/src/io/temp/rgb2temperature.js +30 -0
- simview/static/lib/chroma-js-3.1.2/src/io/temp/temperature2rgb.js +39 -0
- simview/static/lib/chroma-js-3.1.2/src/ops/alpha.js +13 -0
- simview/static/lib/chroma-js-3.1.2/src/ops/clipped.js +5 -0
- simview/static/lib/chroma-js-3.1.2/src/ops/darken.js +17 -0
- simview/static/lib/chroma-js-3.1.2/src/ops/get.js +13 -0
- simview/static/lib/chroma-js-3.1.2/src/ops/luminance.js +54 -0
- simview/static/lib/chroma-js-3.1.2/src/ops/mix.js +10 -0
- simview/static/lib/chroma-js-3.1.2/src/ops/premultiply.js +12 -0
- simview/static/lib/chroma-js-3.1.2/src/ops/saturate.js +15 -0
- simview/static/lib/chroma-js-3.1.2/src/ops/set.js +43 -0
- simview/static/lib/chroma-js-3.1.2/src/ops/shade.js +11 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/analyze.js +191 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/clip_rgb.js +15 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/contrast.js +12 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/contrastAPCA.js +68 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/delta-e.js +62 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/distance.js +17 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/index.js +27 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/last.js +8 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/limit.js +5 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/multiply-matrices.js +36 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/scales.js +15 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/type.js +18 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/unpack.js +17 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/valid.js +11 -0
- simview/static/lib/chroma-js-3.1.2/src/version.js +2 -0
- simview/static/lib/download.js +132 -0
- simview/static/lib/js-colormaps.js +19335 -0
- simview/static/lib/tar.js +334 -0
- simview/static/lib/three-0.174.0/addons/controls/OrbitControls.js +1556 -0
- simview/static/lib/three-0.174.0/addons/libs/lil-gui.module.min.js +8 -0
- simview/static/lib/three-0.174.0/three.core.js +48830 -0
- simview/static/lib/three-0.174.0/three.module.js +17313 -0
- simview/static/lib/uPlot.esm.js +6140 -0
- simview/static/lib/uPlot.min.css +2 -0
- simview/static/textures/contacts/red-cross0.png +0 -0
- simview/static/textures/points/ball0.png +0 -0
- simview/static/textures/points/ball1.png +0 -0
- simview/templates/index.html +81 -0
- simview/utils.py +41 -0
- simview-3.2.dist-info/METADATA +552 -0
- simview-3.2.dist-info/RECORD +163 -0
- simview-3.2.dist-info/WHEEL +5 -0
- simview-3.2.dist-info/entry_points.txt +2 -0
- simview-3.2.dist-info/licenses/LICENSE +28 -0
- simview-3.2.dist-info/top_level.txt +1 -0
simview/state.py
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
from collections.abc import Sequence
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
import torch
|
|
6
|
+
|
|
7
|
+
from simview.model import OptionalBodyStateAttribute, _encode_blob
|
|
8
|
+
|
|
9
|
+
# Accepted array-like input types for authoring calls: torch tensors and numpy
|
|
10
|
+
# arrays are both supported so callers don't need torch just to build a scene.
|
|
11
|
+
ArrayLike = torch.Tensor | np.ndarray
|
|
12
|
+
|
|
13
|
+
# Accepted input types for a body's constant `local_transform`: unlike the
|
|
14
|
+
# ArrayLike-typed per-frame pose/vector fields above (which call `.tolist()`
|
|
15
|
+
# unconditionally and so require an actual tensor/ndarray), `local_transform`
|
|
16
|
+
# is only ever normalized via `hasattr(..., "tolist")` + `list(...)` (see
|
|
17
|
+
# SimViewBody.create), so a plain sequence of floats works too and callers
|
|
18
|
+
# shouldn't need numpy/torch just to pass a constant 7-element offset.
|
|
19
|
+
LocalTransformLike = torch.Tensor | np.ndarray | Sequence[float]
|
|
20
|
+
|
|
21
|
+
# Maps a BodyTrajectory field name to the wire key used in each state's body dict.
|
|
22
|
+
# These are the numeric per-body fields that add_trajectory can pack as binary
|
|
23
|
+
# float32 blobs; contacts are ragged integer lists and stay as JSON.
|
|
24
|
+
TRAJECTORY_VECTOR_FIELDS = {
|
|
25
|
+
"velocity": OptionalBodyStateAttribute.VELOCITY.value,
|
|
26
|
+
"angular_velocity": OptionalBodyStateAttribute.ANGULAR_VELOCITY.value,
|
|
27
|
+
"force": OptionalBodyStateAttribute.FORCE.value,
|
|
28
|
+
"torque": OptionalBodyStateAttribute.TORQUE.value,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# Wire keys SimViewBodyState.to_json() may pack as binary float32 blobs, same
|
|
32
|
+
# set add_trajectory packs. Contacts are ragged (per-batch index lists) and
|
|
33
|
+
# always stay plain JSON.
|
|
34
|
+
_BINARY_ELIGIBLE_FIELDS = {"bodyTransform", *TRAJECTORY_VECTOR_FIELDS.values()}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class BodyTrajectory:
|
|
39
|
+
"""A whole-timeline pose (and optional vectors) for one body.
|
|
40
|
+
|
|
41
|
+
Shapes are ``(T, B, k)`` — T timesteps, B batches — or ``(T, k)`` when the
|
|
42
|
+
scene has a single batch. Orientations are ``[w, x, y, z]`` (scalar-first),
|
|
43
|
+
matching the rest of SimView. Pass a list of these to
|
|
44
|
+
:meth:`SimulationScene.add_trajectory` to append an entire time-series in one
|
|
45
|
+
call instead of building a ``SimViewBodyState`` per frame.
|
|
46
|
+
|
|
47
|
+
``name`` may be a list of body names instead of a single string, to cover
|
|
48
|
+
several bodies that move rigidly together (e.g. links welded to the same
|
|
49
|
+
parent). All named bodies must already exist in the model, and the
|
|
50
|
+
transform/vectors here are applied identically to each of them, avoiding
|
|
51
|
+
the need to duplicate the same data per body.
|
|
52
|
+
|
|
53
|
+
If the named body has a ``parent`` set in the model (see
|
|
54
|
+
``SimulationScene.create_body``), ``positions``/``orientations`` here are
|
|
55
|
+
interpreted as local to that parent's current-frame pose instead of world
|
|
56
|
+
space. A body with a constant ``local_transform`` on the model instead
|
|
57
|
+
must never appear in a ``BodyTrajectory`` at all.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
name: str | list[str]
|
|
61
|
+
positions: ArrayLike # (T, B, 3) or (T, 3)
|
|
62
|
+
orientations: ArrayLike # (T, B, 4) or (T, 4), [w, x, y, z]
|
|
63
|
+
velocity: ArrayLike | None = None # (T, B, 3) or (T, 3)
|
|
64
|
+
angular_velocity: ArrayLike | None = None
|
|
65
|
+
force: ArrayLike | None = None
|
|
66
|
+
torque: ArrayLike | None = None
|
|
67
|
+
# Optional per-timestep contacts: a sequence of length T, where each entry is
|
|
68
|
+
# anything SimViewBodyState._process_contacts accepts for one frame (a (B, N)
|
|
69
|
+
# boolean/float mask, a (B, N) integer index tensor/array, or a list of
|
|
70
|
+
# per-batch index lists). Kept separate from the numeric vector fields above
|
|
71
|
+
# since contacts are ragged and always shipped as plain JSON, never binary.
|
|
72
|
+
contacts: list | None = None
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class SimViewBodyState:
|
|
76
|
+
def __init__(
|
|
77
|
+
self,
|
|
78
|
+
body_name: str | list[str],
|
|
79
|
+
position: ArrayLike,
|
|
80
|
+
orientation: ArrayLike,
|
|
81
|
+
optional_attributes: dict | None = None,
|
|
82
|
+
binary: bool = True,
|
|
83
|
+
):
|
|
84
|
+
"""``body_name`` may be a list of body names sharing this exact
|
|
85
|
+
transform (and any optional attributes), for bodies that move
|
|
86
|
+
rigidly together — see :class:`BodyTrajectory` for the same idea
|
|
87
|
+
applied to whole trajectories.
|
|
88
|
+
|
|
89
|
+
If the named body has a ``parent`` set in the model, ``position``/
|
|
90
|
+
``orientation`` here are interpreted as local to that parent's
|
|
91
|
+
current-frame pose instead of world space (see
|
|
92
|
+
``SimulationScene.create_body``).
|
|
93
|
+
|
|
94
|
+
With ``binary=True`` (the default, matching
|
|
95
|
+
``SimulationScene.add_trajectory``), ``bodyTransform`` and any
|
|
96
|
+
provided vector attributes (velocity/angularVelocity/force/torque)
|
|
97
|
+
are packed as float32 ``__b64__`` blobs, shrinking the output file;
|
|
98
|
+
the viewer and :func:`merge_simulation_files` decode these
|
|
99
|
+
transparently. Set ``binary=False`` to emit plain JSON lists."""
|
|
100
|
+
self.body_name = body_name
|
|
101
|
+
self.position = position.tolist()
|
|
102
|
+
self.orientation = orientation.tolist()
|
|
103
|
+
self.binary = binary
|
|
104
|
+
self._set_optional_attributes(optional_attributes or {})
|
|
105
|
+
|
|
106
|
+
def __repr__(self) -> str:
|
|
107
|
+
return f"SimViewBodyState(name={self.body_name}, position={self.position}, orientation={self.orientation}, optional_attrs={self.optional_attrs})"
|
|
108
|
+
|
|
109
|
+
def _set_optional_attributes(self, attrs):
|
|
110
|
+
self.optional_attrs = {}
|
|
111
|
+
for key, value in attrs.items():
|
|
112
|
+
try:
|
|
113
|
+
key = OptionalBodyStateAttribute(key)
|
|
114
|
+
except ValueError:
|
|
115
|
+
raise ValueError(f"Unknown optional attribute: {key}")
|
|
116
|
+
if key == OptionalBodyStateAttribute.CONTACTS:
|
|
117
|
+
value = self._process_contacts(value)
|
|
118
|
+
elif isinstance(value, (torch.Tensor, np.ndarray)):
|
|
119
|
+
value = value.tolist()
|
|
120
|
+
elif isinstance(value, list):
|
|
121
|
+
if all(isinstance(v, (torch.Tensor, np.ndarray)) for v in value):
|
|
122
|
+
value = [v.tolist() for v in value]
|
|
123
|
+
elif all(isinstance(v, list) for v in value):
|
|
124
|
+
pass
|
|
125
|
+
else:
|
|
126
|
+
raise ValueError("Unknown list format")
|
|
127
|
+
else:
|
|
128
|
+
raise ValueError(f"Unknown attribute type for {key}: {type(value)}")
|
|
129
|
+
self.optional_attrs[key.value] = value
|
|
130
|
+
|
|
131
|
+
@staticmethod
|
|
132
|
+
def _process_contacts(contacts: ArrayLike | list):
|
|
133
|
+
if isinstance(contacts, (torch.Tensor, np.ndarray)): # tensor / array
|
|
134
|
+
if isinstance(contacts, torch.Tensor):
|
|
135
|
+
dtype = contacts.dtype
|
|
136
|
+
is_bool = dtype == torch.bool
|
|
137
|
+
is_float = dtype.is_floating_point
|
|
138
|
+
is_complex = dtype.is_complex
|
|
139
|
+
if is_bool or is_float:
|
|
140
|
+
# Boolean mask (floats treated as a mask of non-zero entries)
|
|
141
|
+
return [
|
|
142
|
+
torch.nonzero(c, as_tuple=True)[0].tolist() for c in contacts
|
|
143
|
+
]
|
|
144
|
+
elif not is_complex: # integer dtype: assume indices
|
|
145
|
+
return contacts.tolist()
|
|
146
|
+
else:
|
|
147
|
+
raise ValueError(f"Unsupported contact tensor dtype: {dtype}")
|
|
148
|
+
else:
|
|
149
|
+
np_dtype = contacts.dtype
|
|
150
|
+
is_bool = np_dtype == np.bool_
|
|
151
|
+
is_float = np.issubdtype(np_dtype, np.floating)
|
|
152
|
+
is_complex = np.issubdtype(np_dtype, np.complexfloating)
|
|
153
|
+
if is_bool or is_float:
|
|
154
|
+
# Boolean mask (floats treated as a mask of non-zero entries)
|
|
155
|
+
return [np.nonzero(c)[0].tolist() for c in contacts]
|
|
156
|
+
elif not is_complex: # integer dtype: assume indices
|
|
157
|
+
return contacts.tolist()
|
|
158
|
+
else:
|
|
159
|
+
raise ValueError(f"Unsupported contact tensor dtype: {np_dtype}")
|
|
160
|
+
else: # list of tensors/arrays or list of lists
|
|
161
|
+
first = contacts[0]
|
|
162
|
+
if isinstance(first, (torch.Tensor, np.ndarray)):
|
|
163
|
+
return [SimViewBodyState._process_contacts(c) for c in contacts]
|
|
164
|
+
elif isinstance(first, list):
|
|
165
|
+
return contacts
|
|
166
|
+
else:
|
|
167
|
+
raise ValueError("Unknown contact format")
|
|
168
|
+
|
|
169
|
+
def to_json(self):
|
|
170
|
+
# Merge position and orientation into bodyTransform
|
|
171
|
+
# position: [x, y, z] or [[x, y, z], ...]
|
|
172
|
+
# orientation: [w, x, y, z] or [[w, x, y, z], ...]
|
|
173
|
+
if len(self.position) > 0 and isinstance(self.position[0], list):
|
|
174
|
+
# Batched
|
|
175
|
+
body_transform = [p + o for p, o in zip(self.position, self.orientation)]
|
|
176
|
+
else:
|
|
177
|
+
# Single
|
|
178
|
+
body_transform = self.position + self.orientation
|
|
179
|
+
|
|
180
|
+
fields = {"bodyTransform": body_transform, **self.optional_attrs}
|
|
181
|
+
if self.binary:
|
|
182
|
+
fields = {
|
|
183
|
+
key: (
|
|
184
|
+
_encode_blob(np.array(value, dtype=np.float32))
|
|
185
|
+
if key in _BINARY_ELIGIBLE_FIELDS
|
|
186
|
+
else value
|
|
187
|
+
)
|
|
188
|
+
for key, value in fields.items()
|
|
189
|
+
}
|
|
190
|
+
return {"name": self.body_name, **fields}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
select {
|
|
2
|
+
background-color: #444;
|
|
3
|
+
color: white;
|
|
4
|
+
border: none;
|
|
5
|
+
border-radius: 4px;
|
|
6
|
+
padding: 5px;
|
|
7
|
+
cursor: pointer;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
select:hover {
|
|
11
|
+
background-color: #555;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
button:hover {
|
|
15
|
+
background-color: #555;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
button:active {
|
|
19
|
+
background-color: #666;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* Add styles for the loading splash screen */
|
|
23
|
+
#loading-splash {
|
|
24
|
+
position: fixed;
|
|
25
|
+
top: 0;
|
|
26
|
+
left: 0;
|
|
27
|
+
width: 100%;
|
|
28
|
+
height: 100%;
|
|
29
|
+
background-color: #000;
|
|
30
|
+
color: #fff;
|
|
31
|
+
display: flex;
|
|
32
|
+
justify-content: center;
|
|
33
|
+
align-items: center;
|
|
34
|
+
z-index: 10000;
|
|
35
|
+
font-family: sans-serif;
|
|
36
|
+
}
|