anythreejs 0.0.1__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.
anythreejs/__init__.py ADDED
@@ -0,0 +1,153 @@
1
+ """
2
+ anythreejs - A modern Python/Three.js bridge for Jupyter
3
+
4
+ Quick start:
5
+ from anythreejs import Renderer, Scene, PerspectiveCamera, OrbitControls
6
+ from anythreejs import Mesh, BoxGeometry, MeshStandardMaterial, AmbientLight
7
+
8
+ scene = Scene(background="#1a1a2e")
9
+ scene.add(Mesh(BoxGeometry(1, 1, 1), MeshStandardMaterial(color="#ff6600")))
10
+ scene.add(AmbientLight(intensity=0.5))
11
+
12
+ camera = PerspectiveCamera(position=(0, 0, 5))
13
+ controls = OrbitControls(controlling=camera)
14
+
15
+ renderer = Renderer(camera=camera, scene=scene, controls=[controls])
16
+ renderer # Display in notebook
17
+
18
+ For pythreejs-style namespace imports:
19
+ import anythreejs as p3
20
+ # Then use p3.Scene, p3.Renderer, etc.
21
+ """
22
+
23
+ from .renderer import Renderer
24
+ from .core import (
25
+ # Base
26
+ ThreeJSBase,
27
+ Object3D,
28
+ # Scene
29
+ Scene,
30
+ # Cameras
31
+ PerspectiveCamera,
32
+ OrthographicCamera,
33
+ # Controls
34
+ OrbitControls,
35
+ TrackballControls,
36
+ # Geometry
37
+ BufferGeometry,
38
+ BoxGeometry,
39
+ BoxBufferGeometry,
40
+ SphereGeometry,
41
+ SphereBufferGeometry,
42
+ PlaneGeometry,
43
+ PlaneBufferGeometry,
44
+ CylinderGeometry,
45
+ CylinderBufferGeometry,
46
+ TorusGeometry,
47
+ EdgesGeometry,
48
+ # Material
49
+ Material,
50
+ MeshBasicMaterial,
51
+ MeshStandardMaterial,
52
+ MeshPhongMaterial,
53
+ MeshLambertMaterial,
54
+ PointsMaterial,
55
+ LineBasicMaterial,
56
+ LineDashedMaterial,
57
+ SpriteMaterial,
58
+ # Objects
59
+ Mesh,
60
+ Points,
61
+ Line,
62
+ LineSegments,
63
+ Group,
64
+ Sprite,
65
+ # Lights
66
+ AmbientLight,
67
+ DirectionalLight,
68
+ PointLight,
69
+ HemisphereLight,
70
+ SpotLight,
71
+ # Helpers
72
+ AxesHelper,
73
+ GridHelper,
74
+ # Buffer
75
+ BufferAttribute,
76
+ Float32BufferAttribute,
77
+ Uint32BufferAttribute,
78
+ Uint16BufferAttribute,
79
+ Int32BufferAttribute,
80
+ # Textures
81
+ TextTexture,
82
+ )
83
+
84
+ # Convenience alias for pythreejs-style imports: `import anythreejs as p3`
85
+ import sys as _sys
86
+
87
+ p3 = _sys.modules[__name__]
88
+
89
+ __version__ = "0.0.1"
90
+
91
+ __all__ = [
92
+ # Renderer
93
+ "Renderer",
94
+ # Base
95
+ "ThreeJSBase",
96
+ "Object3D",
97
+ # Scene
98
+ "Scene",
99
+ # Cameras
100
+ "PerspectiveCamera",
101
+ "OrthographicCamera",
102
+ # Controls
103
+ "OrbitControls",
104
+ "TrackballControls",
105
+ # Geometry
106
+ "BufferGeometry",
107
+ "BoxGeometry",
108
+ "BoxBufferGeometry",
109
+ "SphereGeometry",
110
+ "SphereBufferGeometry",
111
+ "PlaneGeometry",
112
+ "PlaneBufferGeometry",
113
+ "CylinderGeometry",
114
+ "CylinderBufferGeometry",
115
+ "TorusGeometry",
116
+ "EdgesGeometry",
117
+ # Material
118
+ "Material",
119
+ "MeshBasicMaterial",
120
+ "MeshStandardMaterial",
121
+ "MeshPhongMaterial",
122
+ "MeshLambertMaterial",
123
+ "PointsMaterial",
124
+ "LineBasicMaterial",
125
+ "LineDashedMaterial",
126
+ "SpriteMaterial",
127
+ # Objects
128
+ "Mesh",
129
+ "Points",
130
+ "Line",
131
+ "LineSegments",
132
+ "Group",
133
+ "Sprite",
134
+ # Lights
135
+ "AmbientLight",
136
+ "DirectionalLight",
137
+ "PointLight",
138
+ "HemisphereLight",
139
+ "SpotLight",
140
+ # Helpers
141
+ "AxesHelper",
142
+ "GridHelper",
143
+ # Buffer
144
+ "BufferAttribute",
145
+ "Float32BufferAttribute",
146
+ "Uint32BufferAttribute",
147
+ "Uint16BufferAttribute",
148
+ "Int32BufferAttribute",
149
+ # Textures
150
+ "TextTexture",
151
+ # Convenience alias
152
+ "p3",
153
+ ]
@@ -0,0 +1,109 @@
1
+ """
2
+ Core Three.js components.
3
+ """
4
+
5
+ from .base import ThreeJSBase, Object3D
6
+ from .scene import Scene
7
+ from .camera import PerspectiveCamera, OrthographicCamera
8
+ from .controls import OrbitControls, TrackballControls
9
+ from .geometry import (
10
+ BufferGeometry,
11
+ BoxGeometry,
12
+ BoxBufferGeometry,
13
+ SphereGeometry,
14
+ SphereBufferGeometry,
15
+ PlaneGeometry,
16
+ PlaneBufferGeometry,
17
+ CylinderGeometry,
18
+ CylinderBufferGeometry,
19
+ TorusGeometry,
20
+ EdgesGeometry,
21
+ )
22
+ from .material import (
23
+ Material,
24
+ MeshBasicMaterial,
25
+ MeshStandardMaterial,
26
+ MeshPhongMaterial,
27
+ MeshLambertMaterial,
28
+ PointsMaterial,
29
+ LineBasicMaterial,
30
+ LineDashedMaterial,
31
+ SpriteMaterial,
32
+ )
33
+ from .objects import Mesh, Points, Line, LineSegments, Group, Sprite
34
+ from .lights import (
35
+ AmbientLight,
36
+ DirectionalLight,
37
+ PointLight,
38
+ HemisphereLight,
39
+ SpotLight,
40
+ )
41
+ from .helpers import AxesHelper, GridHelper
42
+ from .buffer import (
43
+ BufferAttribute,
44
+ Float32BufferAttribute,
45
+ Uint32BufferAttribute,
46
+ Uint16BufferAttribute,
47
+ Int32BufferAttribute,
48
+ )
49
+ from .textures import TextTexture
50
+
51
+ __all__ = [
52
+ # Base
53
+ "ThreeJSBase",
54
+ "Object3D",
55
+ # Scene
56
+ "Scene",
57
+ # Cameras
58
+ "PerspectiveCamera",
59
+ "OrthographicCamera",
60
+ # Controls
61
+ "OrbitControls",
62
+ "TrackballControls",
63
+ # Geometry
64
+ "BufferGeometry",
65
+ "BoxGeometry",
66
+ "BoxBufferGeometry",
67
+ "SphereGeometry",
68
+ "SphereBufferGeometry",
69
+ "PlaneGeometry",
70
+ "PlaneBufferGeometry",
71
+ "CylinderGeometry",
72
+ "CylinderBufferGeometry",
73
+ "TorusGeometry",
74
+ "EdgesGeometry",
75
+ # Material
76
+ "Material",
77
+ "MeshBasicMaterial",
78
+ "MeshStandardMaterial",
79
+ "MeshPhongMaterial",
80
+ "MeshLambertMaterial",
81
+ "PointsMaterial",
82
+ "LineBasicMaterial",
83
+ "LineDashedMaterial",
84
+ "SpriteMaterial",
85
+ # Objects
86
+ "Mesh",
87
+ "Points",
88
+ "Line",
89
+ "LineSegments",
90
+ "Group",
91
+ "Sprite",
92
+ # Lights
93
+ "AmbientLight",
94
+ "DirectionalLight",
95
+ "PointLight",
96
+ "HemisphereLight",
97
+ "SpotLight",
98
+ # Helpers
99
+ "AxesHelper",
100
+ "GridHelper",
101
+ # Buffer
102
+ "BufferAttribute",
103
+ "Float32BufferAttribute",
104
+ "Uint32BufferAttribute",
105
+ "Uint16BufferAttribute",
106
+ "Int32BufferAttribute",
107
+ # Textures
108
+ "TextTexture",
109
+ ]
@@ -0,0 +1,210 @@
1
+ """
2
+ Base classes for Three.js objects with observable properties.
3
+
4
+ All Three.js objects inherit from these base classes which provide:
5
+ - Property change observation (like ipywidgets traitlets)
6
+ - Serialization to dict for JSON transport to JavaScript
7
+ - UUID for object identification
8
+ """
9
+
10
+ from typing import Any, Callable, Optional
11
+ import uuid
12
+
13
+
14
+ class ThreeJSBase:
15
+ """
16
+ Base class for all Three.js object representations.
17
+
18
+ Provides observable properties and serialization.
19
+ """
20
+
21
+ _type: str = "Object3D"
22
+
23
+ def __init__(self):
24
+ self._uuid = str(uuid.uuid4())
25
+ self._observers: dict[str, list[Callable]] = {}
26
+ self._parent_renderer: Optional[Any] = None
27
+
28
+ @property
29
+ def uuid(self) -> str:
30
+ return self._uuid
31
+
32
+ def observe(self, handler: Callable, names: list[str] | str = None):
33
+ """Register an observer for property changes."""
34
+ if isinstance(names, str):
35
+ names = [names]
36
+ if names is None:
37
+ names = ["_all"]
38
+ for name in names:
39
+ if name not in self._observers:
40
+ self._observers[name] = []
41
+ self._observers[name].append(handler)
42
+
43
+ def unobserve(self, handler: Callable, names: list[str] | str = None):
44
+ """Unregister an observer."""
45
+ if isinstance(names, str):
46
+ names = [names]
47
+ if names is None:
48
+ names = list(self._observers.keys())
49
+ for name in names:
50
+ if name in self._observers and handler in self._observers[name]:
51
+ self._observers[name].remove(handler)
52
+
53
+ def _notify(self, name: str, old: Any, new: Any):
54
+ """Notify observers of a property change."""
55
+ change = {"name": name, "old": old, "new": new, "owner": self}
56
+
57
+ for handler in self._observers.get(name, []):
58
+ handler(change)
59
+ for handler in self._observers.get("_all", []):
60
+ handler(change)
61
+
62
+ if self._parent_renderer is not None:
63
+ self._parent_renderer._request_render()
64
+
65
+ def _set_renderer(self, renderer):
66
+ """Set the parent renderer for sync."""
67
+ self._parent_renderer = renderer
68
+
69
+ def to_dict(self) -> dict[str, Any]:
70
+ """Serialize to dictionary for JSON transport."""
71
+ return {"type": self._type, "uuid": self._uuid}
72
+
73
+
74
+ class Object3D(ThreeJSBase):
75
+ """
76
+ Base class for all 3D objects with transform properties.
77
+ """
78
+
79
+ _type = "Object3D"
80
+
81
+ def __init__(
82
+ self,
83
+ position: tuple | list = (0, 0, 0),
84
+ rotation: tuple | list = (0, 0, 0),
85
+ scale: tuple | list = (1, 1, 1),
86
+ visible: bool = True,
87
+ name: str = "",
88
+ **kwargs,
89
+ ):
90
+ super().__init__()
91
+ self._position = list(position)
92
+ self._rotation = list(rotation)
93
+ self._scale = list(scale)
94
+ self._visible = visible
95
+ self._name = name
96
+ self._children: list["Object3D"] = []
97
+
98
+ @property
99
+ def position(self) -> tuple:
100
+ return tuple(self._position)
101
+
102
+ @position.setter
103
+ def position(self, value):
104
+ old = self._position
105
+ self._position = list(value)
106
+ self._notify("position", old, self._position)
107
+
108
+ @property
109
+ def rotation(self) -> list:
110
+ return self._rotation
111
+
112
+ @rotation.setter
113
+ def rotation(self, value):
114
+ old = self._rotation
115
+ self._rotation = list(value)
116
+ self._notify("rotation", old, self._rotation)
117
+
118
+ @property
119
+ def scale(self) -> list:
120
+ return self._scale
121
+
122
+ @scale.setter
123
+ def scale(self, value):
124
+ old = self._scale
125
+ self._scale = list(value)
126
+ self._notify("scale", old, self._scale)
127
+
128
+ @property
129
+ def visible(self) -> bool:
130
+ return self._visible
131
+
132
+ @visible.setter
133
+ def visible(self, value: bool):
134
+ old = self._visible
135
+ self._visible = value
136
+ self._notify("visible", old, value)
137
+
138
+ @property
139
+ def name(self) -> str:
140
+ return self._name
141
+
142
+ @name.setter
143
+ def name(self, value: str):
144
+ old = self._name
145
+ self._name = value
146
+ self._notify("name", old, value)
147
+
148
+ def rotateX(self, angle: float) -> "Object3D":
149
+ """Rotate around X axis by angle (radians)."""
150
+ self._rotation[0] += angle
151
+ self._notify("rotation", None, self._rotation)
152
+ return self
153
+
154
+ def rotateY(self, angle: float) -> "Object3D":
155
+ """Rotate around Y axis by angle (radians)."""
156
+ self._rotation[1] += angle
157
+ self._notify("rotation", None, self._rotation)
158
+ return self
159
+
160
+ def rotateZ(self, angle: float) -> "Object3D":
161
+ """Rotate around Z axis by angle (radians)."""
162
+ self._rotation[2] += angle
163
+ self._notify("rotation", None, self._rotation)
164
+ return self
165
+
166
+ @property
167
+ def children(self) -> list:
168
+ return self._children
169
+
170
+ def add(self, *objects: "Object3D"):
171
+ """Add child objects. Handles both individual objects and lists."""
172
+ for obj in objects:
173
+ if isinstance(obj, (list, tuple)):
174
+ self.add(*obj)
175
+ elif obj not in self._children:
176
+ self._children.append(obj)
177
+ if self._parent_renderer:
178
+ obj._set_renderer(self._parent_renderer)
179
+ self._notify("children", None, self._children)
180
+
181
+ def remove(self, *objects: "Object3D"):
182
+ """Remove child objects. Handles both individual objects and lists."""
183
+ for obj in objects:
184
+ if isinstance(obj, (list, tuple)):
185
+ self.remove(*obj)
186
+ elif obj in self._children:
187
+ self._children.remove(obj)
188
+ obj._set_renderer(None)
189
+ self._notify("children", None, self._children)
190
+
191
+ def _set_renderer(self, renderer):
192
+ """Recursively set renderer on self and children."""
193
+ super()._set_renderer(renderer)
194
+ for child in self._children:
195
+ child._set_renderer(renderer)
196
+
197
+ def to_dict(self) -> dict[str, Any]:
198
+ data = super().to_dict()
199
+ data.update(
200
+ {
201
+ "position": self._position,
202
+ "rotation": self._rotation,
203
+ "scale": self._scale,
204
+ "visible": self._visible,
205
+ "name": self._name,
206
+ }
207
+ )
208
+ if self._children:
209
+ data["children"] = [child.to_dict() for child in self._children]
210
+ return data
@@ -0,0 +1,89 @@
1
+ """
2
+ Buffer attribute classes for custom geometry data.
3
+ """
4
+
5
+ from typing import Any, Optional, Callable, Union
6
+ import numpy as np
7
+
8
+
9
+ class BufferAttribute:
10
+ """Stores data for BufferGeometry attributes."""
11
+
12
+ def __init__(
13
+ self,
14
+ array: Union[list, np.ndarray],
15
+ itemSize: int = 3,
16
+ normalized: bool = False,
17
+ dtype: str = "float32",
18
+ ):
19
+ self._array = (
20
+ np.array(array, dtype=dtype) if not isinstance(array, np.ndarray) else array
21
+ )
22
+ self._itemSize = itemSize
23
+ self._normalized = normalized
24
+ self._dtype = dtype
25
+ self._on_change: Optional[Callable] = None
26
+
27
+ def _set_on_change(self, callback: Optional[Callable]):
28
+ self._on_change = callback
29
+
30
+ def _notify_change(self):
31
+ if self._on_change:
32
+ self._on_change()
33
+
34
+ @property
35
+ def array(self) -> np.ndarray:
36
+ return self._array
37
+
38
+ @array.setter
39
+ def array(self, value):
40
+ self._array = (
41
+ np.array(value, dtype=self._dtype)
42
+ if not isinstance(value, np.ndarray)
43
+ else value
44
+ )
45
+ self._notify_change()
46
+
47
+ @property
48
+ def itemSize(self) -> int:
49
+ return self._itemSize
50
+
51
+ @property
52
+ def normalized(self) -> bool:
53
+ return self._normalized
54
+
55
+ @property
56
+ def count(self) -> int:
57
+ return len(self._array) // self._itemSize
58
+
59
+ def to_dict(self) -> dict[str, Any]:
60
+ arr = (
61
+ self._array.flatten().tolist()
62
+ if hasattr(self._array, "tolist")
63
+ else self._array
64
+ )
65
+ return {
66
+ "array": arr,
67
+ "itemSize": self._itemSize,
68
+ "normalized": self._normalized,
69
+ }
70
+
71
+
72
+ class Float32BufferAttribute(BufferAttribute):
73
+ def __init__(self, array, itemSize: int = 3, normalized: bool = False):
74
+ super().__init__(array, itemSize, normalized, dtype="float32")
75
+
76
+
77
+ class Uint32BufferAttribute(BufferAttribute):
78
+ def __init__(self, array, itemSize: int = 1, normalized: bool = False):
79
+ super().__init__(array, itemSize, normalized, dtype="uint32")
80
+
81
+
82
+ class Uint16BufferAttribute(BufferAttribute):
83
+ def __init__(self, array, itemSize: int = 1, normalized: bool = False):
84
+ super().__init__(array, itemSize, normalized, dtype="uint16")
85
+
86
+
87
+ class Int32BufferAttribute(BufferAttribute):
88
+ def __init__(self, array, itemSize: int = 1, normalized: bool = False):
89
+ super().__init__(array, itemSize, normalized, dtype="int32")