React Three Fiber and drei (three.js) wrapped as Reflex components.
Project description
reflex-threejs
Interactive three.js for Reflex — in pure Python.
reflex-threejs wraps React Three Fiber (the React
renderer for three.js) and its helper library
drei as idiomatic Reflex components. Build
3D scenes — product viewers, data visualization, generative art, simulations —
without writing a line of JavaScript.
Status: alpha (v0.1.0) — foundation, core components, demo app and full SDD artifacts are in place. See the roadmap.
Why
three.js is the standard for web 3D, but it is imperative and JavaScript-only. React Three Fiber makes it declarative — yet still React/JSX. Reflex compiles Python to React, so wrapping R3F + drei once makes the entire three.js model available to Python developers as ordinary Reflex components.
import reflex as rx
from reflex_threejs import three
def index() -> rx.Component:
return rx.box(
three.canvas(
three.ambient_light(intensity=0.6),
three.directional_light(position=[5, 5, 5], intensity=1.0),
three.mesh(
three.box_geometry(args=[1.5, 1.5, 1.5]),
three.mesh_standard_material(color="#6366f1", metalness=0.3),
),
three.orbit_controls(auto_rotate=True),
camera={"position": [3, 3, 3], "fov": 50},
),
width="100%",
height="600px",
)
app = rx.App()
app.add_page(index)
Features
- Declarative scene graph —
Canvas, meshes, groups, points, lines, sprites, instancing — all from Python. - Full primitive surface — 22 geometries, 14 materials, 6 lights, cameras and
helpers, each accepting three.js constructor
args. - Interaction — pointer events (
on_click,on_pointer_over, …) routed to Reflex event handlers. - State binding — drive any prop (color, transform, …) with a Reflex state Var.
- drei helpers — OrbitControls, Environment/Stage, ContactShadows, Sky, Stars, Text, Html overlay, Float, animated materials and declarative GLTF loading.
- Ergonomic API — flat factories or the
three.*namespace mirroringrx.*. - SSR-safe — the WebGL
Canvasis dynamically imported (ssr:false).
Installation
Not yet on PyPI (planned for v0.2). For now, install from source.
git clone https://github.com/ecrespo/reflex-threejs.git
cd reflex-threejs
pip install -e .
Requires Reflex ≥ 0.7 (React 19). On an older Reflex/React 18 stack, see the compatibility guide.
Run the demo
The demo app showcases nine scenes spanning the main three.js example categories.
cd reflex_threejs_demo
pip install -r requirements.txt # installs reflex + the local package
reflex init # first run only
reflex run
Then open http://localhost:3000.
| Route | Scene | Demonstrates |
|---|---|---|
/ |
Hello Cube | Canvas, lights, mesh, OrbitControls |
/geometries |
Geometry Gallery | built-in geometries |
/materials |
Materials | material types + environment |
/lights |
Lights | ambient/directional/point/spot + shadows |
/interactive |
Interactive | click-to-recolor, hover-to-scale (state events) |
/particles |
Particles | points + buffer geometry |
/staging |
Staging & drei | Stage, ContactShadows, distort material |
/text |
3D Text | drei Text + Float |
/space |
Space | drei Stars, emissive material |
Two ways to use the API
# 1. Namespace (rx-style)
from reflex_threejs import three
three.canvas(three.mesh(three.box_geometry(), three.mesh_normal_material()))
# 2. Flat factories
from reflex_threejs import canvas, mesh, box_geometry, mesh_normal_material
canvas(mesh(box_geometry(), mesh_normal_material()))
drei helpers live under three.drei.* (common ones promoted to three.*).
Documentation
- Usage guide — host elements,
args, events, state binding. - Compatibility guide — React 18/19, R3F v8/v9.
- Spec-Driven Design (SDD) artifacts — the design of this project:
Project layout
reflex-threejs/
├── custom_components/reflex_threejs/ # the component library (Reflex convention)
│ ├── base.py canvas.py objects.py
│ ├── geometries.py materials.py lights.py
│ ├── cameras.py drei.py namespace.py
│ ├── *.pyi py.typed # generated type stubs + PEP 561 marker
│ └── __init__.py
├── reflex_threejs_demo/ # runnable demo app
├── tests/ # contract + quality-gate tests
├── scripts/gen_pyi.py # regenerate the .pyi stubs
├── docs/
│ ├── sdd/ # SDD artifacts
│ └── guides/ # usage & compatibility
├── Makefile pyproject.toml README.md LICENSE CHANGELOG.md
This is the layout produced by reflex component init (package under
custom_components/, a sibling demo app), so it builds and publishes with the
standard Reflex custom-component tooling.
How it works (in one paragraph)
Canvas is wrapped as a Reflex NoSSRComponent, so three.js initializes only in
the browser. Everything inside it — <mesh>, <boxGeometry>,
<meshStandardMaterial>, <ambientLight> — are React Three Fiber host
elements: lowercase intrinsic JSX tags resolved by R3F's reconciler at runtime,
requiring no import. We model these as Reflex components with library = None and
_is_tag_in_global_scope = True, so Reflex emits the tag as a string intrinsic
(jsx("mesh", …)) rather than an undefined component reference. drei helpers are
real exported components, so they declare the @react-three/drei package and an
explicit tag. See the architecture doc for details.
Building & publishing (Reflex custom component)
reflex-threejs is a standard Reflex custom component:
the package lives under custom_components/, ships .pyi type stubs and a
py.typed marker, and builds with the usual tooling.
make install # pip install -e ".[dev]"
make check # ruff + pytest
make stubs # regenerate .pyi stubs after changing any component props
make build # regenerate stubs, then build wheel + sdist, then twine check
make publish # upload to PyPI (needs credentials)
make build is the recommended path: it scopes stub generation to the package.
The official reflex component build does the same two steps (stub generation +
python -m build), but it recursively scans every top-level directory, so run
it only from a clean checkout without local virtualenvs in the tree:
reflex component build # produces dist/ with stubs
python -m twine upload dist/* # or: reflex component share
Bump version in pyproject.toml before publishing. The CI package job
rebuilds the stubs, verifies the committed ones are current, and runs
twine check on every push.
Contributing
Issues and PRs welcome. The design lives in docs/sdd;
please keep specs and code in sync (it's in the Definition of Done). After
changing any component's props, run make stubs and commit the updated .pyi.
License
MIT © 2026 Ernesto Crespo.
Acknowledgements
Built on the work of three.js, pmndrs/react-three-fiber, pmndrs/drei and Reflex.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file reflex_threejs-0.1.0.tar.gz.
File metadata
- Download URL: reflex_threejs-0.1.0.tar.gz
- Upload date:
- Size: 38.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4d8ece5086661bba8eee6e64904e331b3e12efe53a8f6e4b730903e991c64b42
|
|
| MD5 |
d56974585bf2e5d8c60c76f0c35d9b16
|
|
| BLAKE2b-256 |
7a26c9e567ba0008793bbddb04791a337111d2478119af9885f25bd4e93702e2
|
File details
Details for the file reflex_threejs-0.1.0-py3-none-any.whl.
File metadata
- Download URL: reflex_threejs-0.1.0-py3-none-any.whl
- Upload date:
- Size: 38.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
319f39a59952e78d186487058f22c962875fb1cf3e2fdaa5b11228bf5686b1c6
|
|
| MD5 |
35e2c0278e63bf7d67d165369c5a1e99
|
|
| BLAKE2b-256 |
3de092ca283a3be8adf9a8d9a14b3842c3d0a729875eaa63c8be9b31fbbacf0a
|