{"id":15023217,"url":"https://github.com/diptools/dip","last_synced_at":"2026-03-09T06:01:10.077Z","repository":{"id":36968073,"uuid":"494593568","full_name":"diptools/dip","owner":"diptools","description":"Rust application framework focuses on composability, ECS and Web3.  Powered by Bevy game engine, Tauri, and Dioxus. From desktop apps to the Metaverse.","archived":false,"fork":false,"pushed_at":"2024-10-26T17:16:08.000Z","size":11680,"stargazers_count":358,"open_issues_count":28,"forks_count":11,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-01-13T15:24:58.331Z","etag":null,"topics":["bevy-engine","bevy-plugin","cross-platform","declarative-ui","desktop-app","dioxus","ecs","framework","rust"],"latest_commit_sha":null,"homepage":"https://dip.tools","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/diptools.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"JunichiSugiura"}},"created_at":"2022-05-20T20:06:15.000Z","updated_at":"2025-12-18T10:39:12.000Z","dependencies_parsed_at":"2024-10-11T06:01:04.219Z","dependency_job_id":"d13a2412-8eac-4857-adcf-81bdd0f297fe","html_url":"https://github.com/diptools/dip","commit_stats":{"total_commits":239,"total_committers":2,"mean_commits":119.5,"dds":0.004184100418409997,"last_synced_commit":"713682f42b5063d884e0b85f1f75b919ad7ba543"},"previous_names":["junichisugiura/bevy_dioxus"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/diptools/dip","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diptools%2Fdip","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diptools%2Fdip/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diptools%2Fdip/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diptools%2Fdip/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/diptools","download_url":"https://codeload.github.com/diptools/dip/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diptools%2Fdip/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30284628,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-09T02:57:19.223Z","status":"ssl_error","status_checked_at":"2026-03-09T02:56:26.373Z","response_time":61,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bevy-engine","bevy-plugin","cross-platform","declarative-ui","desktop-app","dioxus","ecs","framework","rust"],"created_at":"2024-09-24T19:58:50.807Z","updated_at":"2026-03-09T06:01:10.033Z","avatar_url":"https://github.com/diptools.png","language":"Rust","readme":"\n\u003cdiv align=\"center\"\u003e\n    \u003ch1\u003edip\u003c/h1\u003e\n    \u003cp align=\"center\"\u003e\n        \u003ca href=\"https://crates.io/crates/dip\" alt=\"Crates.io Page\"\u003e\n            \u003cimg src=\"https://img.shields.io/crates/v/dip?style=for-the-badge\u0026color=000\" /\u003e\n        \u003c/a\u003e\n        \u003cimg src=\"https://img.shields.io/crates/d/dip?style=for-the-badge\u0026color=000\" /\u003e\n        \u003cimg src=\"https://img.shields.io/crates/l/dip?style=for-the-badge\u0026color=000\" /\u003e\n        \u003ca href=\"https://github.com/JunichiSugiura/dip/actions/workflows/rust.yml\" alt=\"Github Actions\"\u003e\n            \u003cimg src=\"https://img.shields.io/github/actions/workflow/status/JunichiSugiura/dip/rust.yml?branch=main\u0026style=for-the-badge\u0026logo=github\" /\u003e\n        \u003c/a\u003e\n        \u003ca href=\"https://docs.rs/dip/latest/dip/\" alt=\"API Docs\"\u003e\n            \u003cimg src=\"https://img.shields.io/docsrs/dip?style=for-the-badge\" /\u003e\n        \u003c/a\u003e\n\t\u003c/p\u003e\n    \u003cbr /\u003e\n    \u003cp\u003e\n        Full-Rust Web3 application toolkit focus on\u003cbr /\u003eECS based event-driven development.\n    \u003c/p\u003e\n    \u003cp\u003ePowered by \u003ca href=\"https://github.com/bevyengine/bevy\" alt=\"Bevy  website\"\u003eBevy\u003c/a\u003e game engine.\u003c/p\u003e\n    \u003cp\u003eFrom desktop apps to the Metaverse.\u003c/p\u003e\n    \u003cbr /\u003e\n    \u003cp align=\"center\"\u003e\n        \u003ca href=\"https://discord.gg/4R8AtxAxk3\" alt=\"Discord\"\u003e\n            \u003cimg src=\"https://img.shields.io/discord/1016712886380400651?color=000\u0026label=discord\u0026logo=discord\u0026style=for-the-badge\" /\u003e\n        \u003c/a\u003e\n        \u003ca href=\"https://github.com/orgs/diptools/projects/1\" alt=\"Progress\"\u003e\n            \u003cimg src=\"https://img.shields.io/github/milestones/progress/diptools/dip/1?color=000\u0026style=for-the-badge\" /\u003e\n        \u003c/a\u003e\n    \u003c/p\u003e\n    \u003cp align=\"center\"\u003e\n        \u003ca href=\"https://dip.tools\" alt=\"Website\"\u003e\n            \u003cimg src=\"https://img.shields.io/badge/🌐 Website-000?style=for-the-badge\" /\u003e\n        \u003c/a\u003e\n        \u003ca href=\"https://dip.tools/docs/getting-started/overview/\" alt=\"Documentation\"\u003e\n            \u003cimg src=\"https://img.shields.io/badge/📕 Docs-000?style=for-the-badge\u0026logo=book\" /\u003e\n        \u003c/a\u003e\n        \u003ca href=\"https://docs.rs/dip/latest/dip/\" alt=\"API Refenrence\"\u003e\n            \u003cimg src=\"https://img.shields.io/badge/API Reference-000?style=for-the-badge\u0026logo=docsdotrs\" /\u003e\n        \u003c/a\u003e\n        \u003ca href=\"https://github.com/orgs/diptools/projects/1\" alt=\"Milestone\"\u003e\n            \u003cimg src=\"https://img.shields.io/badge/🏔️ Milestone-000?style=for-the-badge\" /\u003e\n        \u003c/a\u003e\n    \u003c/p\u003e\n\u003c/div\u003e\n\n```rust, no_run\nuse dip::prelude::*;\n\nfn main() {\n    App::new()\n        .insert_resource(WindowDescriptor {\n            title: \"dip Plugin Example\".to_string(),\n            ..Default::default()\n        })\n        .add_plugin(DesktopPlugin::\u003cNoUiState, NoUiAction, NoAsyncAction\u003e::new(Root))\n        .run();\n}\n\nfn Root(cx: Scope) -\u003e Element {\n    cx.render(rsx! {\n        h1 { \"Hello, World !\" }\n    })\n}\n```\n\n- All features are implemented as [Bevy](#bevy) plugins\n- Data-driven ECS design pattern\n- Share your logic between games, desktop apps and command line tools\n- Webview based UI powered by [Tauri](#tauri)\n- React-like declarative UI via [Dioxus](#dioxus)\n- Developer tools\n\t- Bundle: Tools to setup your computer with one command\n\t\t- Homebrew: Installs [Homebrew](https://brew.sh/) formula, cask, mas via `brew bundle`\n\t\t- Symlink manager aka Dotfiles: inspired by [GNU Stow](https://www.gnu.org/software/stow/).\n\t\t- Version Manager: like [`asdf`](https://asdf-vm.com/), [`nvm`](https://github.com/nvm-sh/nvm), `rbenv`, `gvm` etc.\n\t- Device: interact with hardware crypto wallet.\n\n\u003e WARNING: `dip` is still in the very early stages of development.\n\n\u003e `v0.1` is totally a different application. I wanted to make a cross-platform text editor but ended up making this framework.\n\n## Features\n\n### Desktop App\n\n#### Minimum setup with component state\n\n\u003cdetails\u003e\n\u003csummary\u003eCode example\u003c/summary\u003e\n\n```toml\n# Cargo.toml\n\n[dependencies]\ndip = { version = \"0.2\", features = [\"desktop\"] }\n```\n\n```rust, no_run\nuse dip::prelude::*;\n\nfn main() {\n    App::new()\n        .insert_resource(WindowDescriptor {\n            title: \"Desktop App\".to_string(),\n            ..Default::default()\n        })\n        .add_plugin(DesktopPlugin::\u003cNoUiState, NoUiAction, NoAsyncAction\u003e::new(Root))\n        .run();\n}\n\nfn Root(cx: Scope) -\u003e Element {\n    let name = use_state(\u0026cx, || \"world\".to_string());\n\n    cx.render(rsx! {\n        h1 { \"Hello, {name} !\" }\n\n        input {\n            value: \"{name}\",\n            oninput: |e| {\n                name.set(e.value.to_string());\n            },\n        }\n    })\n}\n```\n\n\u003c/details\u003e\n\n#### Keyboard handling\n- [Keyboard event](https://github.com/diptools/dip/blob/main/examples/desktop/keyboard/keyboard_event.rs)\n- [Key bindings](https://github.com/diptools/dip/blob/main/examples/desktop/keyboard/bindings.rs)\n\n\n### CLI App\n\n#### CliPlugin\n\n\u003cdetails\u003e\n\u003csummary\u003eCode example\u003c/summary\u003e\n\n```toml\n# Cargo.toml\n\n[dependencies]\ndip = { version = \"0.2\", features = [\"cli\"] }\nclap = { version = \"3.2\", features = [\"derive\"] }\n```\n\n```rust, no_run\nuse dip::{bevy::log::LogPlugin, prelude::*};\n\nfn main() {\n    App::new()\n        .add_plugin(CliPlugin::\u003cNoAsyncAction\u003e::oneshot())\n        .add_plugin(ActionPlugin)\n        .add_plugin(LogPlugin)\n        .add_system(log_root_arg)\n        .add_system(log_path_flag)\n        .add_system(handle_hello)\n        .add_system(handle_task)\n        .add_system(handle_ping)\n        .run();\n}\n\n#[derive(CliPlugin, clap::Parser)]\n#[clap(author, version, about, long_about = None)]\nstruct Cli {\n    root_arg: Option\u003cString\u003e,\n\n    #[clap(short, long)]\n    path: Option\u003cString\u003e,\n\n    #[clap(subcommand)]\n    action: Action,\n}\n\n#[derive(SubcommandPlugin, clap::Subcommand, Clone)]\npub enum Action {\n    // Named variant\n    Hello { name: Option\u003cString\u003e },\n    // Unnamed\n    Hello2(Hello2Args),\n    // Unit\n    Ping,\n}\n\n#[derive(clap::Args, Debug, Clone)]\npub struct Hello2Args {\n  name: Option\u003cString\u003e,\n}\n\nfn log_root_arg(cli: Res\u003cCli\u003e) {\n    if let Some(arg) = \u0026cli.root_arg {\n        info!(\"root arg: {:?}\", arg);\n    }\n}\n\nfn log_path_flag(cli: Res\u003cCli\u003e) {\n    if let Some(path) = \u0026cli.path {\n        info!(\"path flag: {:?}\", path);\n    }\n}\n\nfn handle_hello(mut events: EventReader\u003cHelloAction\u003e) {\n    for e in events.iter() {\n        info!(\"Hello, {}!\", e.name.clone().unwrap_or(\"world\".to_string()));\n    }\n}\n\nfn handle_task(mut events: EventReader\u003cHello2Action\u003e) {\n    for e in events.iter() {\n        info!(\"Hello, {}!\", e.name.clone().unwrap_or(\"world\".to_string()));\n    }\n}\n\nfn handle_ping(mut events: EventReader\u003cPingAction\u003e) {\n    for _ in events.iter() {\n        info!(\"Pong !\");\n    }\n}\n```\n\n```sh\ncargo run -- --help\n\ndip-cli-example 0.1.0\nJunichi Sugiura\nExample binary project to showcase CliPlugin usage.\n\nUSAGE:\n    cli [OPTIONS] [ROOT_ARG] \u003cSUBCOMMAND\u003e\n\nARGS:\n    \u003cROOT_ARG\u003e\n\nOPTIONS:\n    -h, --help           Print help information\n    -p, --path \u003cPATH\u003e\n    -V, --version        Print version information\n\nSUBCOMMANDS:\n    hello\n    hello2\n    help     Print this message or the help of the given subcommand(s)\n    ping\n\n```\n\u003c/details\u003e\n\n### State management (Inspired by Redux)\n\n#### UiStatePlugin, UiActionPlugin\n\n\u003cdetails\u003e\n\u003csummary\u003eCode example\u003c/summary\u003e\n\n```toml\n# Cargo.toml\n\n[dependencies]\ndip = { version = \"0.2\", features = [\"desktop\"] }\n\n# Removing this crate throws error.\n# This is because some derive macros generates code using sub crate name instead of root\n# (e.x. bevy_ecs::Component vs bevy::ecs::Compoent)\nbevy_ecs = \"0.8\"\n```\n\n```rust, no_run\nuse dip::prelude::*;\n\nfn main() {\n    App::new()\n        // Step 7. Put it all together\n        .add_plugin(DesktopPlugin::\u003cUiState, UiAction, NoAsyncAction\u003e::new(Root))\n        .add_plugin(UiStatePlugin) // generated by #[ui_state]\n        .add_plugin(UiActionPlugin) // generated by #[ui_action]\n        .add_system(update_name)\n        .run();\n}\n\n// Step 1: Define UiState\n// Each field represents root state. You can create multiple of them.\n// This macro generates UiState enum and UiStatePlugin which will be used in step 7.\n#[ui_state]\nstruct UiState {\n    name: Name,\n}\n\n// Make sure to wrap primitive types or common type such as String with named struct or enum.\n// You need to distinguish types in order to query specific root state in step 4 (system).\n#[derive(Clone, Debug)]\npub struct Name {\n    value: String,\n}\n\n// This is how you define default value for Name root state.\nimpl Default for Name {\n    fn default() -\u003e Self {\n        Self {\n            value: \"world\".to_string(),\n        }\n    }\n}\n\n// Step 2. Define actions\n// Create as many as actions with struct or enum.\n#[derive(Clone, Debug)]\npub struct UpdateName {\n    value: String,\n}\n\n// Step 3. Implement action creators\n// Each method needs to return one of actions that you defined in step 2.\n// This macro derives UiActionPlugin and UiAction which will be used in step 7.\n#[ui_action]\nimpl ActionCreator {\n    fn update_name(value: String) -\u003e UpdateName {\n        UpdateName { value }\n    }\n}\n\n// Step 4. Implement systems to handle each action defined in step 2.\n// System is like reducer in Redux but more flexible.\nfn update_name(mut events: EventReader\u003cUpdateName\u003e, mut name: ResMut\u003cName\u003e) {\n    for action in events.iter() {\n        name.value = action.value.clone();\n    }\n}\n\nfn Root(cx: Scope) -\u003e Element {\n    // Step 5. Select state\n    let name = use_read(\u0026cx, NAME);\n\n    let window = use_window::\u003cUiAction, NoAsyncAction\u003e(\u0026cx);\n\n    cx.render(rsx! {\n        h1 { \"Hello, {name.value} !\" }\n\n        input {\n            value: \"{name.value}\",\n            oninput: |e| {\n                // Step 6. Dispatch the action !\n                window.send(UiAction::update_name(e.value.to_string()));\n            },\n        }\n    })\n}\n```\n\n\u003c/details\u003e\n\n## About Bevy and Dioxus\n\n### Bevy\n\n[https://github.com/bevyengine/bevy](https://github.com/bevyengine/bevy)\n- Data-driven game engine based on Entity Component System(ECS) design pattern\n- Flexible Plugin design\n- Plugin ecosystem\n\nBevy is a cutting-edge game engine in Rust based on Entity Component System(ECS) design pattern. Think of it as a global state management tool like Redux but much more performant because all systems will run as parallel as possible. Thanks to its plugin system, there's already a handful of third-party Bevy plugins out there. Imagine implementing core logic as `CorePlugin` separated from UI layer. You may start with `dip::desktop` to build desktop application. Then let's say you want to release a metaverse edition at some point in the future, it's as simple as swapping UI plugin to Bevy's 3d rendering plugin while still using the same CorePlugin.\n\n### Tauri\n\n- [TAO](https://github.com/tauri-apps/tao)\n- [WRY](https://github.com/tauri-apps/wry)\n\nTao is a window manager and the fork of `winit`. `DesktopPlugin` depends on this library to render webview. And the webview is powered by WRY which is essentailly a Rust wrapper around OS specific webview.\n\n#### Why not Tauri?\n\nIf you want to write frontend in any languages other than Rust, then Tauri is a better fit! If you want to go full Rust, then that's where `dip` shines.\n\n### Dioxus\n\n[https://github.com/DioxusLabs/dioxus](https://github.com/DioxusLabs/dioxus)\n- Cross-platform (macOS, Linux, Windows, TUI, etc.)\n- React-like declarative UI library\n- Virtual dom is 3x faster than React\n- Minimum bundle size is around 20x lighter than Electron (8 MB vs 160MB)\n\nDioxus is a cross-platform declarative UI library. It provides familiar features that React developer expects such as component, state, props, hooks, global state, and router. If you familiar with any modern state driven UI framework, you should be able to read or write Dioxus components without knowing Rust. \n\n## Examples\n\nMake sure to install all prerequisites for Tauri.\n- [Prerequisites](https://tauri.studio/v1/guides/getting-started/prerequisites)\n\n\n### Clone repository\n\n```sh\ngh repo clone diptools/dip\ncd dip\n```\n\n### Counter example\n\n```sh\ncargo run --example counter --features desktop\n```\n\n\u003e Find more in [examples/](https://github.com/diptools/dip/tree/main/examples) directory.\n\n### TodoMVC example\n\n1. Install dip CLI.\n\n```sh\ncargo install dip\n\n# or install local binary\ncargo install --path .\n```\n\n2. Compile Tailwind CSS\n\n```sh\ndip build -p examples/todomvc\n```\n\n3. Run\n\n```sh\ncargo run -p todomvc\n```\n","funding_links":["https://github.com/sponsors/JunichiSugiura"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiptools%2Fdip","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdiptools%2Fdip","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiptools%2Fdip/lists"}