Asteroid is a desktop application for creating interactive, model-driven diagrams, specifically designed for visualizing Tropos and i* (i-star) methodologies. It supports actor-agent relationships, dependencies, goals, resources, and more.
Built with Python and PyQt6, it follows a clean MVC-inspired architecture that strictly separates core models, UI components, and controllers for maximum modularity and maintainability.
🌐 Visit the official website | 📥 Download latest release
- Interactive QGraphicsView canvas with:
- Drag & drop nodes from a sidebar (Actor, Agent, Goal, Resource, Softgoal, Plan)
- Support for simple and dashed arrows (dependencies, contributions, means-end)
- Zoom in/out, pan, and reset view
- PDF Export with two modes:
- Diagram image only
- Diagram + detailed element information (classification and relationships)
- Built-in help system with Markdown documentation
- Logical models decoupled from graphical representation (
Actor≠ActorNodeItem) - Controller layer managing interactions between UI and domain logic (MVC pattern)
- Extensible design: Easily add new node types, edge styles, or behaviors
- Built for collaboration: Clear separation enables team development and testing
- Type safety: Full type annotations with mypy validation (0 errors, strict mode compatible)
- Windows 10/11 executable
- Linux (.deb package for Debian/Ubuntu)
- macOS app bundle
asteroid/
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── app/
│ ├── __init__.py
│ ├── model_types.py # Type definitions for models
│ ├── controller_types.py # Type definitions for controllers
│ ├── controllers/ # Canvas logic (MVC pattern)
│ │ ├── __init__.py
│ │ ├── _canvas_mixin.py # Mixin for shared controller logic
│ │ ├── canvas_controller.py # Orchestrator: combines all controllers
│ │ ├── canvas_deletion_controller.py # Delete nodes/edges/selection
│ │ ├── canvas_export_controller.py # Export to .astr or image
│ │ ├── canvas_import_controller.py # Import from .astr
│ │ ├── canvas_interaction_controller.py # Node and arrow interaction
│ │ ├── canvas_node_controller.py # Add/move nodes
│ │ ├── canvas_registry_controller.py # Node/edge type registration
│ │ └── canvas_state_controller.py # Project state (modified/saved)
│ ├── core/ # Domain models (business logic)
│ │ ├── __init__.py
│ │ └── models/
│ │ ├── __init__.py
│ │ ├── base_node.py # Base class for all nodes
│ │ ├── base_edge.py # Base class for all edges
│ │ ├── composite_model_wrapper.py # Syncs external/internal models
│ │ ├── dependency/ # Dependency models
│ │ │ ├── __init__.py
│ │ │ ├── simple_edge.py
│ │ │ ├── dashed_edge.py
│ │ │ ├── dependency_link_edge.py
│ │ │ ├── why_link_edge.py
│ │ │ ├── means_end_edge.py
│ │ │ ├── or_decomposition_edge.py
│ │ │ ├── and_decomposition_edge.py
│ │ │ └── contribution_edge.py
│ │ ├── entity/ # Entity models
│ │ │ ├── __init__.py
│ │ │ ├── actor.py
│ │ │ └── agent.py
│ │ └── tropos_element/ # Tropos element models
│ │ ├── __init__.py
│ │ ├── hard_goal.py
│ │ ├── soft_goal.py
│ │ ├── plan.py
│ │ └── resource.py
│ ├── ui/ # PyQt6 interface (View)
│ │ ├── __init__.py
│ │ ├── canvas.py # Main QGraphicsView
│ │ ├── main_window.py # Main window
│ │ ├── pdf_export_dialog.py # PDF export dialog
│ │ ├── sidebar.py # Sidebar with draggable elements
│ │ ├── components/
│ │ │ ├── __init__.py
│ │ │ ├── base_node_item.py # Base for node items
│ │ │ ├── base_edge_item.py # Base for edge items
│ │ │ ├── base_tropos_item.py # Base for Tropos items
│ │ │ ├── control_point_handle.py # Control point handle
│ │ │ ├── subcanvas_item.py # Subcanvas item
│ │ │ ├── position_controll_widget.py # Position control widget
│ │ │ ├── properties_panel.py # Properties panel
│ │ │ ├── dependency_item/ # Edge items
│ │ │ │ ├── __init__.py
│ │ │ │ ├── simple_edge_item.py
│ │ │ │ ├── dashed_edge_item.py
│ │ │ │ ├── dependency_link_edge_item.py
│ │ │ │ ├── why_link_edge_item.py
│ │ │ │ ├── means_end_edge_item.py
│ │ │ │ ├── or_decomposition_edge_item.py
│ │ │ │ ├── and_decomposition_edge_item.py
│ │ │ │ └── contribution_edge_item.py
│ │ │ ├── entity_item/ # Entity items
│ │ │ │ ├── __init__.py
│ │ │ │ ├── actor_node_item.py
│ │ │ │ └── agent_node_item.py
│ │ │ └── tropos_element_item/ # Tropos element items
│ │ │ ├── __init__.py
│ │ │ ├── hard_goal_item.py
│ │ │ ├── soft_goal_item.py
│ │ │ ├── plan_item.py
│ │ │ └── resource_item.py
│ │ └── help/ # Help system
│ │ ├── help_modal.py
│ │ ├── markdown_viewer.py
│ │ └── content/
│ │ ├── about.md
│ │ ├── elements.md
│ │ ├── examples.md
│ │ └── quick_help.md
│ └── utils/ # Utils (serialization, export)
│ ├── astr_format.py # .astr serializer
│ └── pdf_export.py # PDFs generator
├── images/
│ ├── AsteroidLogo.png
│ ├── main_interface_example1.png
│ ├── main_interface_example2.png
│ └── main_interface_example3.png
├── main.py
├── pyproject.toml
└── uv.lock
| Requirement | Version |
|---|---|
| Python | 3.12.3+ |
| PyQt6 | 6.8.0+ |
| numpy | 2.0.0+ |
| reportlab | 4.2.0+ |
| markdown | 3.7+ |
# Install uv (if not already installed)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Clone and run
git clone https://github.com/DaryllLorenzo/asteroid.git
cd asteroid
uv run main.py# Clone the repository
git clone https://github.com/DaryllLorenzo/asteroid.git
cd asteroid
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # Linux/macOS
# .venv\Scripts\activate # Windows
# Install dependencies
pip install markdown numpy pyqt6 reportlab
# Run the application
python main.py💡 Tip: Option 1 with
uvis faster and ensures reproducible dependencies.
| Main Interface | Actor with Subcanvas |
|---|---|
![]() |
![]() |
- Actor/agent node movement within subcanvas
- Configurable text size for components
- Multi-line text labels in nodes
- Softgoal visual component improvements
- Cross-platform packaging (Windows, Linux, macOS)
- Keyboard shortcuts system
- Flexible link shapes (user-draggable control points for edges)
- Visual themes (light/dark mode)
- Model validation (Tropos methodology consistency)
- Undo/redo history for all actions
- Diagram templates for common Tropos patterns
- Multi-language support (English, Spanish) with language switcher
Contributions are welcome! Here's how you can help:
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Commit your changes:
git commit -m 'Add amazing feature' - Push:
git push origin feature/amazing-feature - Open a Pull Request
Please read our contributing guidelines for more details.
Found a bug? Have a feature request? Open an issue with a clear description and, if possible, steps to reproduce.
Distributed under the MIT License. See LICENSE for more information.
- Author: Daryll Lorenzo
- Project Website: https://darylllorenzo.github.io/asteroid-landing/
- GitHub Repository: https://github.com/DaryllLorenzo/asteroid
Built with PyQt6, special thanks to the Qt and Python communities.



