Skip to main content

reflex-resium

Quality Security PyPI

Resium (React components for 🌏 Cesium) wrapped for Reflex: build 3D globes and maps — entities, primitives, GeoJSON/KML/CZML, 3D Tiles, terrain, camera flights, post-processing — in pure Python.

  • All 97 resium components (resium 1.26.0 / cesium 1.145.0), generated from resium's TypeScript definitions with prop docs and types.
  • rs.Cesium bridge: build real Cesium objects (Cartesian3, Color, imagery providers, materials, enums…) from Python, including state vars and rx.foreach items.
  • Automatic memoization of Cesium objects so read-only props don't re-create elements on every render.
  • JSON-safe events: Cesium callbacks (on_click, on_load, on_tick, on_ready…) arrive in your state as dictionaries.
  • cesium_events: geographic clicks / mouse moves (longitude, latitude, height, picked entity), camera changes and selection.
  • Imperative helpers: fly_to, set_view, fly_home, zoom_to_entity, morph_to, set_clock, get_camera, screenshot.
  • ResiumPlugin: serves Cesium's static assets locally in dev and copies them into production builds (without it, the jsDelivr CDN is used).

Installation

pip install reflex-resium     # or: uv add reflex-resium

Quick start

import reflex as rx
import reflex_resium as rs


def index() -> rx.Component:
    return rx.box(
        rs.viewer(
            rs.entity(
                rs.point_graphics(pixel_size=12, color=rs.Cesium.Color.RED),
                rs.entity_description(rx.heading("Tokyo"), rx.text("Hello from Reflex!")),
                name="Tokyo",
                position=rs.cartesian3(139.767052, 35.681167, 100),
            ),
            full=True,
        ),
        position="relative",
        height="100vh",
    )


app = rx.App()
app.add_page(index)

rxconfig.py (recommended):

import reflex as rx
from reflex_resium import ResiumPlugin

config = rx.Config(
    app_name="my_app",
    plugins=[rx.plugins.RadixThemesPlugin(), ResiumPlugin()],
)

Concepts

Components

Every resium component is available as a class (rs.Viewer) and a snake_case factory (rs.viewer). Props are snake_case (pixel_sizepixelSize). Nest them exactly like in resium:

rs.viewer(
    rs.custom_data_source(rs.entity(...), name="points"),
    rs.camera_fly_to(destination=rs.cartesian3(-66.9, 10.48, 50_000), duration=3),
    rs.globe(enable_lighting=True),
    rs.bloom(enabled=State.bloom),
    full=True,
)

Props named style that are Cesium values (Cesium3DTileset, Label, WMTS…) are exposed as cesium_style; root components (viewer, cesium_widget) keep Reflex's style, id and class_name.

The rs.Cesium bridge

C = rs.Cesium
C.Cartesian3.fromDegrees(State.lon, State.lat, 1000)
C.Color.fromCssColorString("#22d3ee").withAlpha(0.5)
C.HeightReference.CLAMP_TO_GROUND
C.OpenStreetMapImageryProvider.new(url="https://tile.openstreetmap.org/")  # new X({url})
C.Material.fromType("Checkerboard", {"repeat": rs.cartesian2(20, 10)})
rs.js("Array.from({length: 8}, (_, i) => i)")  # raw JS escape hatch

Keyword arguments become a camelCase options object. Helpers: cartesian3, cartesian3_array, cartesian3_array_heights, cartesian2, color, rectangle_from_degrees, heading_pitch_roll, heading_pitch_range, camera_orientation, near_far_scalar, distance_display_condition, bounding_sphere, julian_date, time_interval_collection, ion_resource, natural_earth_imagery_layer, osm_imagery_layer, url_template_imagery_layer, ion_imagery_layer, world_terrain, ellipsoid_terrain.

Cesium expressions passed as props are wrapped in useMemo (dependencies = the state vars they use). Use .volatile() to opt out or .memo(*deps) for explicit dependencies.

Events

class State(rx.State):
    @rx.event
    def clicked(self, movement: dict, target: dict):
        # movement = {"position": {"x", "y"}, ...}; target = {"id", "name", "kind", "properties"}
        ...


rs.entity(..., on_click=State.clicked)
rs.geo_json_data_source(data="/data.geojson", on_load=State.loaded)  # {"name", "entity_count", ...}
rs.clock(on_tick=State.tick.throttle(1000))  # throttle high-frequency events

Geographic events and imperative camera control

rs.viewer(
    ...,
    rs.cesium_events(
        viewer_id="main",
        on_left_click=State.on_click,  # {"longitude", "latitude", "height", "screen", "picked"}
        on_mouse_move=State.on_move,  # throttled (mouse_move_throttle=100 ms)
        on_camera_change=State.on_camera,  # {"longitude", "latitude", "height", "heading", "pitch", "roll"}
        on_selected_entity_change=State.on_select,
    ),
)

rx.button("Caracas", on_click=rs.fly_to("main", -66.9, 10.48, 20_000, pitch=-35, duration=3))
rx.button("Photo", on_click=rs.screenshot("main", State.save_png))

Notes and gotchas

  • Camera operations (camera_fly_to, camera_look_at, camera_fly_home, camera_fly_to_bounding_sphere) run in resium on every render. The wrappers memoize them (callbacks ignored in the comparison), so they only run again when a real prop changes.
  • cesium_widget wraps its children with CesiumWidgetContext, exposing Cesium's entities/dataSources, which resium only provides for viewer.
  • entity_description renders into Cesium's InfoBox iframe: Emotion/Radix classes don't apply there, so use rx.el.* with inline styles (custom_attrs={"style": {...}}).
  • ParticleSystem advances with the scene clock: it needs should_animate=True.
  • In development React StrictMode mounts components twice, so load events (on_load, on_ready) may fire twice; production builds fire once.

Cesium assets and ion token

Cesium needs its Workers, Assets, ThirdParty and Widgets folders at runtime (CESIUM_BASE_URL):

Setup Assets served from
ResiumPlugin() node_modules/cesium/Build/Cesium via a Vite middleware in dev; copied to cesium/ in reflex export
ResiumPlugin(base_url="https://my.cdn/cesium/") your URL
no plugin CESIUM_BASE_URL env var, else jsDelivr CDN

Cesium ion assets (world terrain, OSM Buildings, Bing imagery) need a token: ResiumPlugin(ion_access_token="...") or the CESIUM_ION_ACCESS_TOKEN environment variable. Without it Cesium's evaluation token is used and a banner is shown. natural_earth_imagery_layer() works offline with no token.

Demo

cd resium_demo
uv pip install -e ..   # or pip install -e ..
reflex run

Pages: entities & state · entity graphics · primitives & clouds · data sources (GeoJSON, KML, CZML, clustering) · camera & events · scene & post-processing & particles · imagery, glTF models & 3D Tiles · CesiumWidget.

Regenerating the wrappers

custom_components/reflex_resium/components.py is generated:

# in a scratch folder with resium, cesium, react and typescript@5 installed
node scripts/extract_props.mjs                 # -> props.json
python scripts/generate_components.py props.json path/to/resium/src

Development

uv sync                                          # project + locked dev tools (uv.lock)
uv run ruff check . && uv run ruff format --check .  # lint + format
uv run pytest                                    # tests

CI runs on every push/PR to develop and main:

  • Quality (.github/workflows/quality.yml): Ruff (version locked in uv.lock), pytest on Python 3.10–3.13, uv build + twine check + wheel smoke test, demo compilation.
  • Security (.github/workflows/security.yml): Bandit, pip-audit, Gitleaks, dependency review and CodeQL (also weekly).

Releasing

Bump __version__ in custom_components/reflex_resium/__init__.py, merge to main, then tag it:

git tag v0.1.0 && git push origin v0.1.0

.github/workflows/release.yml checks that the tag matches the version, tests and builds the package, publishes it to PyPI through Trusted Publishing (environment pypi) and creates the GitHub Release with the distributions attached.

License

MIT © Ernesto Crespo. Resium and Cesium are licensed under MIT and Apache-2.0 respectively.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

reflex_resium-0.1.0.tar.gz (116.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

reflex_resium-0.1.0-py3-none-any.whl (117.6 kB view details)

Uploaded Python 3

File details

Details for the file reflex_resium-0.1.0.tar.gz.

File metadata

  • Download URL: reflex_resium-0.1.0.tar.gz
  • Upload date:
  • Size: 116.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for reflex_resium-0.1.0.tar.gz
Algorithm Hash digest
SHA256 565cb126b782913810e2bf420437db92e8abc5687f4ca705b03bf9e470776472
MD5 562ba2bedd772882606fc3280283e26a
BLAKE2b-256 4a3f900db9bb4154a1935496fc67fb10d73c721bd664b1e4ed158dc14ded1812

See more details on using hashes here.

Provenance

The following attestation bundles were made for reflex_resium-0.1.0.tar.gz:

Publisher: release.yml on ecrespo/reflex-resium

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file reflex_resium-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: reflex_resium-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 117.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for reflex_resium-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c03d13b0547594e331c3fe9638e398ece77cfa79659e214bad0513fc8d020ccc
MD5 3c3017b085307e33f85e8279b36af3ce
BLAKE2b-256 d75f88d82a70b4403c2d1a51a09e5908578d2f8629dc7747d4131ed32ddae07a

See more details on using hashes here.

Provenance

The following attestation bundles were made for reflex_resium-0.1.0-py3-none-any.whl:

Publisher: release.yml on ecrespo/reflex-resium

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page