Planet

View Planet

.. toc::

.. llms_copy::Planet

dash-planet is a Dash component library that provides an interactive orbital menu system for creating engaging circular navigation interfaces. It displays content elements (satellites) in a circular orbit around a central element with smooth spring-based animations. The component offers both free and premium tiers, supporting basic orbital menus with up to 3 satellites for free, and unlimited satellites with advanced features like draggable elements, semicircle layouts, and enhanced animation controls with a premium API key.

Installation

[Visit GitHub Repo](https://github.com/pip-install-python/dash_planet)

⭐️ Star this component on GitHub! Stay up to date on new releases and browse the codebase.

``bash pip install dash-planet ``

---

Quick Start

Create a basic interactive orbital menu with a central avatar and satellite action buttons.

.. exec::docs.dash_planet.introduction :code: false

```python

File: docs/dash_planet/introduction.py

import dash from dash import html, Input, Output, State, callback, dcc, ALL from dash_planet import DashPlanet from dash_iconify import DashIconify import json import dash_mantine_components as dmc import os from dotenv import load_dotenv from pathlib import Path

env_path = Path('.') / '.env' load_dotenv(env_path)

API_KEY = os.getenv("API_KEY")

Set React version

_dash_renderer._set_react_version("18.3.1")

Get API URL from environment or use default

app = dash.Dash(__name__, suppress_callback_exceptions=True)

Enable CORS for development

app.enable_dev_tools(

dev_tools_hot_reload=True,

dev_tools_props_check=True,

dev_tools_serve_dev_bundles=True,

dev_tools_prune_errors=False

)

Rest of your styles remain the same...

styles = { "container": { "width": "100%", "height": "100vh", "display": "flex", "flexDirection": "column", "alignItems": "center", "justifyContent": "center", "padding": "20px", }, "header": { "textAlign": "center", "marginBottom": "20px", "width": "100%", "maxWidth": "600px", }, "apiInput": { "width": "100%", "maxWidth": "400px", "padding": "8px", "marginBottom": "10px", "border": "1px solid #ccc", "borderRadius": "4px", }, "description": { "fontSize": "14px", "color": "#666", "marginBottom": "20px", "textAlign": "center", }, "demoArea": { "display": "flex", "width": "100%", "height": "500px", # Fixed height for demo area "backgroundColor": "white", "justifyContent": "center", "alignItems": "center", "position": "relative", }, "planet": { "height": "120px", "width": "120px", "borderRadius": "50%", "backgroundColor": "#1976d2", "display": "flex", "justifyContent": "center", "alignItems": "center", "color": "white", "cursor": "pointer", "transition": "all 0.3s", "position": "relative", }, "satellite": { "height": "40px", "width": "40px", # 'borderRadius': '50%', # 'backgroundColor': '#ff4081', "display": "flex", "justifyContent": "center", "alignItems": "center", "color": "white", "cursor": "pointer", "zIndex": 1, }, "gridColumn": { "height": "300px", "width": "100%", "display": "flex", "justifyContent": "center", "alignItems": "center", "position": "relative", "padding": "20px", "boxSizing": "border-box", }, }

def generate_satellites(count): """Generate satellite elements with icons""" icons = [ "fxemoji:email", "noto:calendar", "emojione-v1:bar-chart", "emojione:gear", "flat-color-icons:file", "emojione-v1:open-folder", "twemoji:heart-on-fire", "flat-color-icons:home", ] return [ html.Div( [ DashIconify( icon=icons[i % len(icons)], width=40, height=40, color="white" ) ], style=styles["satellite"], id={"type": "satellite", "index": i}, ) for i in range(count) ]

forms_props = dmc.GridCol( children=[

dmc.Paper( children=[ dmc.Stack( [ dmc.Text("Props Control Panel", size="xl", fw=700, ta="center"), dmc.Grid( [ dmc.GridCol( dmc.Stack( [ # Physics Controls dmc.Text( "Physics", fw=700, size="sm", c="dimmed" ), dmc.Group( [ dmc.NumberInput( id="mass-input", label="Mass", value=1, min=1, max=10, step=0.5, style={"width": 100}, ), dmc.NumberInput( id="tension-input", label="Tension", value=200, min=100, max=1000, step=50, style={"width": 100}, ), dmc.NumberInput( id="friction-input", label="Friction", value=32, min=1, max=50, step=1, style={"width": 100}, ), ] ), ] ), span={"xs": 12, "md": 6}, ), dmc.GridCol( dmc.Stack( [ # Orbit Controls dmc.Text( "Orbit", fw=700, size="sm", c="dimmed", mt="md", ), dmc.Group( [ dmc.NumberInput( id="orbit-radius-input", label="Radius", value=80, min=40, max=200, step=10, style={"width": 100}, ), dmc.NumberInput( id="rotation-input", label="Rotation", value=0, min=0, max=360, step=15, style={"width": 100}, ), ] ), ] ), span={"xs": 12, "md": 6}, ), ], grow=True, ), dmc.Grid( [ dmc.GridCol( dmc.Stack( [ dmc.Text( "Rotation Animation (Works in production not in Docs)", fw=700, size="sm", c="dimmed", mt="md", ), dmc.Group( [ dmc.Switch( id="animate-rotation-input", label="Animate Rotation", checked=False, ), dmc.NumberInput( id="rotation-speed-input", label="Speed", value=2, min=0.1, max=10, step=0.1, style={"width": 100}, ), ] ), ] ), span={"xs": 12, "md": 6}, ), dmc.GridCol( dmc.Stack( [ # Animation Controls dmc.Text( "Animation", fw=700, size="sm", c="dimmed", mt="md", ), dmc.Group( [ dmc.Switch( id="bounce-input", label="Bounce", checked=True, ), dmc.Switch( id="hide-orbit-input", label="Hide Orbit", checked=True, ), ] ), ] ), span={"xs": 12, "md": 6}, ), ] ), dmc.Grid( [ dmc.GridCol( # Satellite Orientation dmc.Select( id="satellite-orientation-input", label="Satellite Orientation", data=[ {"value": "DEFAULT", "label": "Default"}, {"value": "INSIDE", "label": "Inside"}, {"value": "OUTSIDE", "label": "Outside"}, {"value": "READABLE", "label": "Readable"}, ], value="DEFAULT", style={"width": "100%"}, ), span={"xs": 12, "md": 12}, ) ] ), dcc.Interval( id="rotation-interval", interval=50, # 50ms = 20fps disabled=True, ), ] ), ], p="md", shadow="sm", radius="md", withBorder=True, style={"maxWidth": "100%", "width": "100%"}, ) ], style={ "height": "100%", "display": "flex", "justifyContent": "center", "alignItems": "center", "position": "relative", "overflow": "auto", }, span={"base": 12, "xl": 4}, )

Create layout

component = dmc.Box( [ dmc.Stack( [ html.H1("DashPlanet Demo", style={"marginBottom": "10px"}), html.P( [ "Free tier includes up to 3 satellites. ", "Enter an API key to unlock all features.", ], style=styles["description"], ), dmc.Group( [ dcc.Input( id="api-key-input", type="text", placeholder="Enter your API key to check if it works", value="", style={'display': 'none'} ), dmc.Switch( id="use-env-api-key", label="Use Environment API Key", checked=False, ), ], justify="center", ), html.Div( id="api-key-status", style={"color": "#666", "marginBottom": "10px"} ),

], justify="center", align="center", gap="md", ), dmc.Space(h=20), dmc.Grid( children=[ forms_props, dmc.GridCol( dmc.Stack( [ dmc.Space(h=50), dmc.Box( DashPlanet( id="demo-planet", centerContent=dmc.Indicator( dmc.Avatar( size="lg", radius="xl", src="https://raw.githubusercontent.com/mantinedev/mantine/master/.demo/avatars/avatar-3.png", ), inline=True, offset=7, position="bottom-end", color="red", withBorder=True, size=16, ), open=True, orbitRadius=80, hideOrbit=True, bounce=True, bounceOnOpen=True, rotation=0, dragablePlanet=True, dragableSatellites=True, satelliteOrientation="DEFAULT", children=generate_satellites(8), mass=4, tension=500, friction=19, apiKey="", ), style={ "width": "100%", "maxWidth": "500px", "margin": "0 auto", "display": "flex", "justifyContent": "center", "alignItems": "center", "minHeight": "300px", } ), dmc.Space(h=150), html.Div( [ # API validation status html.Div(id="validation-status"), dmc.Text( "Click a satellite to see its function", id="action-text", ta="center", ), ] ), ], mt="100px", ), span={"base": 12, "xl": 4}, style={ "height": "100%", "display": "flex", "justifyContent": "center", "alignItems": "center", "position": "relative", "padding": "20px", "boxSizing": "border-box", }, ), dmc.GridCol( dmc.Card( [ dmc.Text("Features", size="xl", fw=700, mb="md"), dmc.Stack( [ dmc.Group( [ DashIconify(icon="mdi:check", width=20), dmc.Text("Free Tier: Up to 3 satellites"), ], gap="xs", ), dmc.Group( [ DashIconify(icon="mdi:star", width=20), dmc.Text("Premium: Unlimited satellites"), ], gap="xs", ), dmc.Group( [ DashIconify(icon="fxemoji:crescentmoon", width=20), dmc.Text("Premium: Semicircle Menu layout"), ], gap="xs", ), dmc.Group( [ DashIconify(icon="mdi:animation", width=20), dmc.Text("Premium: Enhanced animation controls"), ], gap="xs", ), dmc.Group( [ DashIconify(icon="fluent-emoji:sparkling-heart", width=20), dmc.Text("Supports independent Dash Components development"), ], gap="xs", ), dmc.Divider(), dmc.HoverCard( withArrow=True, width=200, shadow="md", children=[ dmc.HoverCardTarget( dmc.Group( [ DashIconify(icon="cib:buy-me-a-coffee", width=20), dmc.Anchor( "Buy a DashPlanet API key", href="https://plotly.pro/product/prod_SY2xOUihEmOKda", target="_blank", size="md", ), ], gap="xs", ) ), dmc.HoverCardDropdown( dmc.Image( radius="md", src="/assets/images/tippy.png", ) ), ], ), ], gap="sm", ), ], p="xl", shadow="sm", radius="md", withBorder=True, style={"width": "100%"} ), style={ "display": "flex", "justifyContent": "center", "alignItems": "center", "position": "relative", "padding": "20px", "boxSizing": "border-box", }, span={"base": 12, "xl": 4}, ), ], gutter="xl", ), ] )

Update callbacks

@callback( [ Output("demo-planet", "apiKey"), Output("api-key-input", "disabled"), Output("api-key-status", "children"), Output("api-key-status", "style"), ], [ Input("api-key-input", "value"), Input("use-env-api-key", "checked") ], prevent_initial_call=True, ) def update_api_key(api_key, use_env_key): """Update API key based on input or environment variable""" if use_env_key: return API_KEY, True, "Demo using a paid API key", {"color": "#4CAF50"}

if not api_key: return None, False, "Using free tier", {"color": "#666"}

return api_key, False, f"Using API key: {api_key[:8]}...", {"color": "#4CAF50"}

@callback( Output("demo-planet", "open"), Input("demo-planet", "n_clicks"), prevent_initial_call=True, ) def toggle_planet(n_clicks): """Toggle planet open/closed state""" if n_clicks is None: return dash.no_update return n_clicks % 2 == 1

Add this callback to handle satellite clicks

@callback( Output("action-text", "children"), Input({"type": "satellite", "index": ALL}, "n_clicks"), prevent_initial_call=True, ) def handle_satellite_click(clicks): ctx = dash.callback_context if not ctx.triggered: return "Click a satellite to see its function"

triggered_id = ctx.triggered[0]["prop_id"].split(".")[0] satellite_index = json.loads(triggered_id)["index"]

# Map indices to actions actions = [ "Compose new email", "Open calendar", "View analytics", "Open settings", "New document", "Browse files", "Favorite item", "Return home", ]

return f"Selected: {actions[satellite_index % len(actions)]}"

Add these callbacks after your existing callbacks:

@callback( Output("demo-planet", "mass"), Input("mass-input", "value"), prevent_initial_call=True, ) def update_mass(value): return value

@callback( Output("demo-planet", "tension"), Input("tension-input", "value"), prevent_initial_call=True, ) def update_tension(value): return value

@callback( Output("demo-planet", "friction"), Input("friction-input", "value"), prevent_initial_call=True, ) def update_friction(value): return value

@callback( Output("demo-planet", "orbitRadius"), Input("orbit-radius-input", "value"), prevent_initial_call=True, ) def update_orbit_radius(value): return value

@callback( Output("demo-planet", "rotation"), Input("rotation-input", "value"), prevent_initial_call=True, ) def update_rotation(value): return value

@callback( Output("demo-planet", "bounce"), Input("bounce-input", "checked"), prevent_initial_call=True, ) def update_bounce(checked): return checked

@callback( Output("demo-planet", "hideOrbit"), Input("hide-orbit-input", "checked"), prevent_initial_call=True, ) def update_hide_orbit(checked): return checked

@callback( Output("demo-planet", "satelliteOrientation"), Input("satellite-orientation-input", "value"), prevent_initial_call=True, ) def update_satellite_orientation(value): return value

@callback( [Output("rotation-interval", "disabled"), Output("rotation-input", "disabled")], Input("animate-rotation-input", "checked"), ) def toggle_animation(animate): return not animate, animate

Callback to update rotation based on the interval

@callback( Output("demo-planet", "rotation", allow_duplicate=True), [Input("rotation-interval", "n_intervals"), Input("rotation-speed-input", "value")], State("demo-planet", "rotation"), prevent_initial_call=True, ) def update_rotation(n_intervals, speed, current_rotation): if current_rotation is None: current_rotation = 0 # Calculate new rotation angle new_rotation = (current_rotation + speed) % 360 return new_rotation

Callback to handle manual rotation input

@callback( Output("rotation-input", "disabled", allow_duplicate=True), Input("animate-rotation-input", "checked"), prevent_initial_call=True, ) def toggle_rotation_input(animate): return animate ```

---

Basic Code Example

Here's a minimal example to get started with DashPlanet:

```python from dash import Dash from dash_planet import DashPlanet import dash_mantine_components as dmc from dash_iconify import DashIconify

app = Dash(__name__)

app.layout = DashPlanet( id='my-planet', centerContent=dmc.Avatar( size="lg", radius="xl", src="path/to/avatar.png" ), children=[ dmc.ActionIcon( DashIconify(icon="clarity:settings-line", width=20, height=20), size="lg", variant="filled", id="action-icon-1", ), dmc.ActionIcon( DashIconify(icon="mdi:email", width=20, height=20), size="lg", variant="filled", id="action-icon-2", ), dmc.ActionIcon( DashIconify(icon="mdi:bell", width=20, height=20), size="lg", variant="filled", id="action-icon-3", ), ], orbitRadius=80, rotation=0, )

if __name__ == '__main__': app.run_server(debug=True) ```

---

Semicircle Menu Layout

Premium feature that displays satellites in a semicircle layout instead of full circular orbit. Perfect for creating arc-shaped menus and navigation bars.

.. exec::docs.dash_planet.semicircle_example :code: false

```python

File: docs/dash_planet/semicircle_example.py

import dash from dash import html, Input, Output, State, callback, dcc from dash_planet import DashPlanet from dash_iconify import DashIconify import dash_mantine_components as dmc import os from dotenv import load_dotenv from pathlib import Path

env_path = Path('.') / '.env' load_dotenv(env_path)

API_URL = os.getenv("API_URL") API_KEY = os.getenv("API_KEY")

styles = { 'root': { 'display': 'flex', 'flex': '1', 'width': '100%', 'justifyContent': 'center', 'alignItems': 'center', 'flexDirection': 'column', 'position': 'relative', 'gap': '20px' }, 'satellite': { 'height': '40px', 'width': '40px', 'display': 'flex', 'justifyContent': 'center', 'alignItems': 'center', 'color': 'white', 'cursor': 'pointer', 'zIndex': 1 } }

def generate_satellites(count, empty_divs=5): """Generate satellite elements with icons""" icons = [ "fxemoji:email", "noto:calendar", "emojione-v1:bar-chart", "emojione:gear", "flat-color-icons:file", "emojione-v1:open-folder", "twemoji:heart-on-fire", "flat-color-icons:home", ]

empty_div_style = { 'width': '40px', 'height': '40px', 'transition': 'transform 0.3s ease-in-out' }

return [ html.Div([ DashIconify(icon=icons[i % len(icons)], width=40, height=40, color="white") ], style=styles['satellite'], id={'type': 'satellite', 'index': i}) for i in range(count) ] + [html.Div(style=empty_div_style) for _ in range(empty_divs)]

component = dmc.Box([ dcc.Input( id='api-key-input', type='text', value='O3iEIQMkVzbbdgs-ZSfBotNt3WoLhqGjID0fMrhuN64', style={'display': 'none'} ),

dmc.Grid([ # Add form controls dmc.GridCol([ dmc.Paper([ dmc.Text("Menu Semicircle Controls", size="lg", fw=500, ta="center", mb="md"), dmc.NumberInput( id="menu-planet-empty-divs-input", label="Number of Empty Divs", value=5, min=0, max=10, step=1, mb="sm" ), dmc.NumberInput( id="menu-planet-rotation-input", label="Rotation (degrees)", value=0, min=0, max=360, step=45, mb="sm" ), dmc.NumberInput( id="menu-planet-orbit-radius-input", label="Orbit Radius", value=80, min=40, max=200, step=10, mb="sm" ), ], p="md", shadow="sm", radius="md", withBorder=True, style={"width": "100%"}) ], span={'base': 12, 'lg': 5}),

dmc.GridCol([ dmc.Box( DashPlanet( id='menu-planet', centerContent=dmc.Indicator( dmc.Avatar( size="lg", radius="xl", src="https://raw.githubusercontent.com/mantinedev/mantine/master/.demo/avatars/avatar-3.png", ), inline=True, offset=7, position="bottom-end", color="red", withBorder=True, size=16, ), open=True, orbitRadius=80, hideOrbit=True, bounce=True, bounceOnOpen=True, rotation=90, dragablePlanet=True, dragableSatellites=True, satelliteOrientation='DEFAULT', children=generate_satellites(3), mass=4, tension=500, friction=19, apiKey=API_KEY ), style={ "width": "100%", "maxWidth": "500px", "margin": "0 auto", "display": "flex", "justifyContent": "center", "alignItems": "center", "minHeight": "300px", } ) ], style={ 'display': 'flex', 'flex': '1', 'width': '100%', 'justifyContent': 'center', 'alignItems': 'center', 'flexDirection': 'column', 'position': 'relative', 'gap': '20px', 'padding': '20px', 'boxSizing': 'border-box' }, span={'base': 12, 'lg': 7}), ], gutter="md") ])

@callback( Output('menu-planet', 'children'), Output('menu-planet', 'rotation'), Input('menu-planet-empty-divs-input', 'value'), Input('menu-planet-rotation-input', 'value') ) def update_satellites(empty_divs, rotation): return generate_satellites(3, empty_divs), rotation

@callback( Output("menu-planet", "orbitRadius"), Input("menu-planet-orbit-radius-input", "value"), prevent_initial_call=True, ) def update_orbit_radius(value): return value ```

---

Free vs Premium Features

DashPlanet offers both free and premium tiers to suit different project needs.

| Free Tier | Premium Features | |:-----------------------------------------|:----------------| | ✓ Up to 3 satellite elements in orbit | 🌟 Unlimited satellite elements | | ✓ Basic orbital animation | 🌙 Semicircle Menu layout | | ✓ Customizable orbit radius and rotation | ⚡ Enhanced animation controls | | ✓ Click-to-toggle functionality | 💎 Draggable satellites and center element | | | 🎯 Bounce animations with directional control | | | 🔄 Advanced satellite orientation options |

Get Premium Access: [Buy DashPlanet API Key](https://plotly.pro/product/prod_SY2xOUihEmOKda)

To use premium features, provide your API key:

``python DashPlanet( apiKey="your-api-key-here", # Premium features now available dragableSatellites=True, bounce=True, bounceDirection="TOP", ) ``

---

Working with Callbacks

Toggle Orbital Menu:

Control the visibility of satellite elements using the open property and n_clicks callback.

```python from dash import Input, Output, callback

@callback( Output("my-planet", "open"), Input("my-planet", "n_clicks") ) def toggle_planet(n_clicks): """Toggle satellite visibility on center element click""" if n_clicks is None: return False return n_clicks % 2 == 1 ```

Dynamic Rotation Control:

Update the orbital rotation angle dynamically based on user input.

``python @callback( Output("my-planet", "rotation"), Input("rotation-slider", "value") ) def update_rotation(value): """Rotate the entire orbital system""" return value ``

Satellite Click Handling:

Respond to clicks on individual satellite elements by giving each satellite a unique ID.

```python @callback( Output("output-div", "children"), Input("satellite-1", "n_clicks"), Input("satellite-2", "n_clicks"), Input("satellite-3", "n_clicks"), ) def handle_satellite_clicks(n1, n2, n3): """Handle clicks on different satellites""" ctx = callback_context if not ctx.triggered: return "Click a satellite"

button_id = ctx.triggered[0]["prop_id"].split(".")[0] return f"Clicked: {button_id}" ```

---

Customizing Satellite Elements

Satellites can be any valid Dash component, allowing for rich, interactive menu items.

Using Icons:

```python from dash_iconify import DashIconify from dash import html

satellites = [ html.Div([ DashIconify( icon="mdi:email", width=40, height=40, color="#3b82f6" ) ], style={'width': '40px', 'height': '40px'}) for _ in range(3) ] ```

Using Mantine Components:

```python import dash_mantine_components as dmc

satellites = [ dmc.ActionIcon( dmc.ThemeIcon(DashIconify(icon="mdi:home")), size="lg", variant="filled", color="blue", ), dmc.ActionIcon( dmc.ThemeIcon(DashIconify(icon="mdi:settings")), size="lg", variant="filled", color="green", ), ] ```

---

Animation Controls

Fine-tune the spring physics animation using mass, tension, and friction properties.

``python DashPlanet( mass=4, # Higher mass = slower, heavier animation tension=500, # Higher tension = stiffer spring, faster animation friction=19, # Higher friction = more damping, less bounce ) ``

Animation Parameter Guide:

- Lower values (0.5-1): Light, quick animations - Higher values (2-5): Heavy, slower animations

- Lower values (100-300): Looser, more elastic - Higher values (500-1000): Tighter, snappier

- Lower values (5-15): More bouncy, oscillating - Higher values (20-30): Smoother, more damped

---

Styling and Appearance

Component Styling:

Apply custom styles to the container using the style prop:

``python DashPlanet( style={ 'backgroundColor': '#f8f9fa', 'borderRadius': '50%', 'boxShadow': '0 4px 6px rgba(0, 0, 0, 0.1)', 'padding': '20px', } ) ``

Hiding the Orbit Line:

Toggle the visibility of the orbital path line:

``python DashPlanet( hideOrbit=True, # Hide the circular orbit line ) ``

Satellite Orientation (Premium):

Control how satellites rotate as they orbit:

``python DashPlanet( apiKey="your-key", satelliteOrientation="READABLE", ) ``

---

Browser Support

DashPlanet is compatible with modern browsers that support CSS transforms and React Spring animations:

Minimum Requirements:

---

Component Properties

| Property | Type | Default | Description | | :----------------- | :---------- | :----------- | :-------------------------------------------------------------------------------------------------------------- | | id | string | Required | Unique identifier for the component used in Dash callbacks. | | centerContent | node | None | Content displayed in the center of the orbit (e.g., avatar, button, icon). | | children | node | None | Satellite elements to be displayed in orbit around the center. Can be any valid Dash components. | | open | bool | False | Controls visibility of satellite elements. Set to True to show satellites, False to hide. | | orbitRadius | number | 120 | Radius of the orbit in pixels. Determines how far satellites are from the center. | | rotation | number | 0 | Initial rotation angle of the orbital system in degrees. Use to offset starting positions. | | hideOrbit | bool | False | If True, hides the circular orbit line. Satellites still orbit, but the path is invisible. | | mass | number | 1 | Mass parameter for spring physics animation. Higher values create heavier, slower animations. | | tension | number | 500 | Spring tension parameter. Higher values create stiffer, faster animations. | | friction | number | 17 | Spring friction parameter. Higher values create more damping and reduce bounce. | | style | dict | {} | Standard CSS styles to apply to the component container. | | className | string | None | CSS class name to apply to the component container. | | n_clicks | number | 0 | Number of times the center element has been clicked. Updates automatically on click. | | apiKey | string | None | API key for unlocking premium features. Purchase at [plotly.pro](https://plotly.pro/product/prod_SY2xOUihEmOKda) | | dragablePlanet | bool | False | (Premium) Enable dragging of the center element. Requires valid apiKey. | | dragableSatellites | bool | False | (Premium) Enable dragging of satellite elements. Requires valid apiKey. | | bounce | bool | False | (Premium) Enable bounce animation effect. Requires valid apiKey. | | bounceDirection | string | "TOP" | (Premium) Direction of bounce animation. Options: "TOP", "BOTTOM", "LEFT", "RIGHT". Requires apiKey. | | satelliteOrientation | string | "DEFAULT" | (Premium) How satellites rotate in orbit. Options: "DEFAULT", "INSIDE", "OUTSIDE", "READABLE". Requires apiKey. | | setProps | func | (Dash Internal) | Callback function to update component properties. | | loading_state | object | (Dash Internal) | Object describing the loading state of the component or its props. |

Note: Premium features marked with (Premium) require a valid API key. Free tier is limited to 3 satellite elements maximum.

---

Contributing

Contributions to dash-planet are welcome! Please refer to the project's issues on GitHub for any feature requests or bug reports.

License

This project is licensed under the MIT License.

Note for AI agents: This is the static, prerendered view of an interactive Dash application served because we detected a non-JS user agent. Full prose docs: