# Planet > Interactive orbital menu component with circular satellite layout, spring animations, and premium features --- .. 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, _dash_renderer 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, _dash_renderer, 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:** - **`mass`**: Controls the "weight" of the animation (default: 1) - Lower values (0.5-1): Light, quick animations - Higher values (2-5): Heavy, slower animations - **`tension`**: Controls spring stiffness (default: 500) - Lower values (100-300): Looser, more elastic - Higher values (500-1000): Tighter, snappier - **`friction`**: Controls damping/resistance (default: 17) - 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: - **`DEFAULT`**: No rotation, satellites maintain upright position - **`INSIDE`**: Satellites face toward the center - **`OUTSIDE`**: Satellites face away from the center - **`READABLE`**: Satellites rotate to remain readable (top half upright, bottom half inverted) ```python DashPlanet( apiKey="your-key", satelliteOrientation="READABLE", ) ``` --- ### Browser Support DashPlanet is compatible with modern browsers that support CSS transforms and React Spring animations: - Chrome (latest) - Firefox (latest) - Safari (latest) - Edge (latest) **Minimum Requirements:** - `dash` ≥ 2.0.0 - `react` ≥ 18.3.1 --- ### 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. --- *Source: /pip/dash_planet* *Generated with dash-improve-my-llms*