Dip
Rust application framework focuses on composability, ECS and Web3. Powered by Bevy game engine, Tauri, and Dioxus. From desktop apps to the Metaverse.
Install / Use
/learn @diptools/DipREADME
<div align="center">
<h1>dip</h1>
<p align="center">
<a href="https://crates.io/crates/dip" alt="Crates.io Page">
<img src="https://img.shields.io/crates/v/dip?style=for-the-badge&color=000" />
</a>
<img src="https://img.shields.io/crates/d/dip?style=for-the-badge&color=000" />
<img src="https://img.shields.io/crates/l/dip?style=for-the-badge&color=000" />
<a href="https://github.com/JunichiSugiura/dip/actions/workflows/rust.yml" alt="Github Actions">
<img src="https://img.shields.io/github/actions/workflow/status/JunichiSugiura/dip/rust.yml?branch=main&style=for-the-badge&logo=github" />
</a>
<a href="https://docs.rs/dip/latest/dip/" alt="API Docs">
<img src="https://img.shields.io/docsrs/dip?style=for-the-badge" />
</a>
</p>
<br />
<p>
Full-Rust Web3 application toolkit focus on<br />ECS based event-driven development.
</p>
<p>Powered by <a href="https://github.com/bevyengine/bevy" alt="Bevy website">Bevy</a> game engine.</p>
<p>From desktop apps to the Metaverse.</p>
<br />
<p align="center">
<a href="https://discord.gg/4R8AtxAxk3" alt="Discord">
<img src="https://img.shields.io/discord/1016712886380400651?color=000&label=discord&logo=discord&style=for-the-badge" />
</a>
<a href="https://github.com/orgs/diptools/projects/1" alt="Progress">
<img src="https://img.shields.io/github/milestones/progress/diptools/dip/1?color=000&style=for-the-badge" />
</a>
</p>
<p align="center">
<a href="https://dip.tools" alt="Website">
<img src="https://img.shields.io/badge/🌐 Website-000?style=for-the-badge" />
</a>
<a href="https://dip.tools/docs/getting-started/overview/" alt="Documentation">
<img src="https://img.shields.io/badge/📕 Docs-000?style=for-the-badge&logo=book" />
</a>
<a href="https://docs.rs/dip/latest/dip/" alt="API Refenrence">
<img src="https://img.shields.io/badge/API Reference-000?style=for-the-badge&logo=docsdotrs" />
</a>
<a href="https://github.com/orgs/diptools/projects/1" alt="Milestone">
<img src="https://img.shields.io/badge/🏔️ Milestone-000?style=for-the-badge" />
</a>
</p>
</div>
use dip::prelude::*;
fn main() {
App::new()
.insert_resource(WindowDescriptor {
title: "dip Plugin Example".to_string(),
..Default::default()
})
.add_plugin(DesktopPlugin::<NoUiState, NoUiAction, NoAsyncAction>::new(Root))
.run();
}
fn Root(cx: Scope) -> Element {
cx.render(rsx! {
h1 { "Hello, World !" }
})
}
- All features are implemented as Bevy plugins
- Data-driven ECS design pattern
- Share your logic between games, desktop apps and command line tools
- Webview based UI powered by Tauri
- React-like declarative UI via Dioxus
- Developer tools
WARNING:
dipis still in the very early stages of development.
v0.1is totally a different application. I wanted to make a cross-platform text editor but ended up making this framework.
Features
Desktop App
Minimum setup with component state
<details> <summary>Code example</summary># Cargo.toml
[dependencies]
dip = { version = "0.2", features = ["desktop"] }
use dip::prelude::*;
fn main() {
App::new()
.insert_resource(WindowDescriptor {
title: "Desktop App".to_string(),
..Default::default()
})
.add_plugin(DesktopPlugin::<NoUiState, NoUiAction, NoAsyncAction>::new(Root))
.run();
}
fn Root(cx: Scope) -> Element {
let name = use_state(&cx, || "world".to_string());
cx.render(rsx! {
h1 { "Hello, {name} !" }
input {
value: "{name}",
oninput: |e| {
name.set(e.value.to_string());
},
}
})
}
</details>
Keyboard handling
CLI App
CliPlugin
<details> <summary>Code example</summary># Cargo.toml
[dependencies]
dip = { version = "0.2", features = ["cli"] }
clap = { version = "3.2", features = ["derive"] }
use dip::{bevy::log::LogPlugin, prelude::*};
fn main() {
App::new()
.add_plugin(CliPlugin::<NoAsyncAction>::oneshot())
.add_plugin(ActionPlugin)
.add_plugin(LogPlugin)
.add_system(log_root_arg)
.add_system(log_path_flag)
.add_system(handle_hello)
.add_system(handle_task)
.add_system(handle_ping)
.run();
}
#[derive(CliPlugin, clap::Parser)]
#[clap(author, version, about, long_about = None)]
struct Cli {
root_arg: Option<String>,
#[clap(short, long)]
path: Option<String>,
#[clap(subcommand)]
action: Action,
}
#[derive(SubcommandPlugin, clap::Subcommand, Clone)]
pub enum Action {
// Named variant
Hello { name: Option<String> },
// Unnamed
Hello2(Hello2Args),
// Unit
Ping,
}
#[derive(clap::Args, Debug, Clone)]
pub struct Hello2Args {
name: Option<String>,
}
fn log_root_arg(cli: Res<Cli>) {
if let Some(arg) = &cli.root_arg {
info!("root arg: {:?}", arg);
}
}
fn log_path_flag(cli: Res<Cli>) {
if let Some(path) = &cli.path {
info!("path flag: {:?}", path);
}
}
fn handle_hello(mut events: EventReader<HelloAction>) {
for e in events.iter() {
info!("Hello, {}!", e.name.clone().unwrap_or("world".to_string()));
}
}
fn handle_task(mut events: EventReader<Hello2Action>) {
for e in events.iter() {
info!("Hello, {}!", e.name.clone().unwrap_or("world".to_string()));
}
}
fn handle_ping(mut events: EventReader<PingAction>) {
for _ in events.iter() {
info!("Pong !");
}
}
cargo run -- --help
dip-cli-example 0.1.0
Junichi Sugiura
Example binary project to showcase CliPlugin usage.
USAGE:
cli [OPTIONS] [ROOT_ARG] <SUBCOMMAND>
ARGS:
<ROOT_ARG>
OPTIONS:
-h, --help Print help information
-p, --path <PATH>
-V, --version Print version information
SUBCOMMANDS:
hello
hello2
help Print this message or the help of the given subcommand(s)
ping
</details>
State management (Inspired by Redux)
UiStatePlugin, UiActionPlugin
<details> <summary>Code example</summary># Cargo.toml
[dependencies]
dip = { version = "0.2", features = ["desktop"] }
# Removing this crate throws error.
# This is because some derive macros generates code using sub crate name instead of root
# (e.x. bevy_ecs::Component vs bevy::ecs::Compoent)
bevy_ecs = "0.8"
use dip::prelude::*;
fn main() {
App::new()
// Step 7. Put it all together
.add_plugin(DesktopPlugin::<UiState, UiAction, NoAsyncAction>::new(Root))
.add_plugin(UiStatePlugin) // generated by #[ui_state]
.add_plugin(UiActionPlugin) // generated by #[ui_action]
.add_system(update_name)
.run();
}
// Step 1: Define UiState
// Each field represents root state. You can create multiple of them.
// This macro generates UiState enum and UiStatePlugin which will be used in step 7.
#[ui_state]
struct UiState {
name: Name,
}
// Make sure to wrap primitive types or common type such as String with named struct or enum.
// You need to distinguish types in order to query specific root state in step 4 (system).
#[derive(Clone, Debug)]
pub struct Name {
value: String,
}
// This is how you define default value for Name root state.
impl Default for Name {
fn default() -> Self {
Self {
value: "world".to_string(),
}
}
}
// Step 2. Define actions
// Create as many as actions with struct or enum.
#[derive(Clone, Debug)]
pub struct UpdateName {
value: String,
}
// Step 3. Implement action creators
// Each method needs to return one of actions that you defined in step 2.
// This macro derives UiActionPlugin and UiAction which will be used in step 7.
#[ui_action]
impl ActionCreator {
fn update_name(value: String) -> UpdateName {
UpdateName { value }
}
}
// Step 4. Implement systems to handle each action defined in step 2.
// System is like reducer in Redux but more flexible.
fn update_name(mut events: EventReader<UpdateName>, mut name: ResMut<Name>) {
for action in events.iter() {
name.value = action.value.clone();
}
}
fn Root(cx: Scope) -> Element {
// Step 5. Select state
let name = use_read(&cx, NAME);
let window = use_window::<UiAction, NoAsyncAction>(&cx);
cx.render(rsx! {
h1 { "Hello, {name.value} !" }
input {
value: "{name.value}",
oninput: |e| {
// Step 6. Dispatch the action !
window.send(UiAction::update_name(e.value.to_string()));
},
}
})
}
</details>
About Bevy and Dioxus
Bevy
https://github.com/bevyengine/bevy
- Data-driven game engine based on Entity Component System(ECS) design pattern
- Flexible Plugin design
- Plugin ecosystem
Bevy 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
