Chisle
The coding-agent plugin that bills 52% of a bare model across 20 live tasks. Terse persona + tool-output compressor + context diet.
翻訳待ち
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗cargo add bevy_iroh # rooms, presence, replication, messages, voice, video, screens, the panel
cargo add bevy_iroh --no-default-features # the transport alone
cargo add bevy_iroh --no-default-features -F media # plus voice and video without the Bevy UI
Live demos, in a browser tab: rvdende.github.io/bevy_iroh. Code and issues: github.com/rvdende/bevy_iroh.
Share Bevy entities between peers over iroh: QUIC dialled by public
key, hole punching with relay fallback, gossip for the room, direct streams for one peer. No
server. Tag an entity Shared and everyone in the room has it; give it Voice and a
VideoFeed and they hear and see you, from a camera or a shared screen.
use bevy::prelude::*;
use bevy_iroh::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Component, Serialize, Deserialize, Clone)]
struct Cube;
fn main() {
App::new()
.add_plugins((DefaultPlugins, IrohPlugin::default()))
.replicate::<Cube>() // Transform is replicated by default
.add_systems(Startup, setup)
.add_observer(on_add_cube)
.run();
}
fn setup(mut commands: Commands) {
match std::env::args().nth(1) {
Some(t) => commands.spawn(Room::join(t.parse().unwrap())),
None => commands.spawn(Room::host("hello")), // a `Ticket` appears on the entity
};
// Mine. Peers get `Cube`, `Transform` and `Owner`, and keep up as it moves.
commands.spawn((Cube, Shared::default(), Transform::from_xyz(0.0, 0.5, 0.0)));
}
// Runs for my cube and for every cube a peer sends: one code path for visuals.
fn on_add_cube(add: On<Add, Cube>, mut commands: Commands /* , meshes, materials */) {
commands.entity(add.entity).insert((/* Mesh3d, MeshMaterial3d */));
}
Run cargo run --example cube, copy the ticket it prints, and run it again with the ticket on
another machine. Each sees the other's cube glide as its owner drives it with the arrow keys.
IrohPlugin | one tokio thread owning the endpoint; Identity::{Ephemeral, File, Key}; Relays::{N0, Extend, Only, Disabled}; with_protocol(alpn, handler) (or with_protocol_factory) for your own ALPNs on the same endpoint; with_autostart(false) to stay off the network until StartIroh is queued, and StopIroh to go off it again |
Room | an entity, not a place: Room::host(name) / Room::join(ticket), then RoomStatus, Ticket, RoomTopic on it. Despawn it to leave |
Peer | one entity per remote member per room, MemberOf(room); PeerJoined / PeerLeft messages; heartbeats every 5 s, reaped after three silent ones |
Shared | replicate this entity into every room I am in, or the one it is InRoom. NetId is its identity across peers (NetId::keyed("floor") for one that everyone spawns), Owner who made it, Remote on replicas |
replicate::<T>() | derive serde and T crosses. replicate_with(codec) for anything else: a quantised form, validation, a component from another crate, a smoothing target on arrival (Codec has Source, Wire, Target) |
Transform | 20 Hz, replicas ease toward each arrival over an interval learned from real gaps; never extrapolates |
add_net_message::<T>() | typed messages: NetSender::broadcast is gossip to the room, send_to dials one peer; read Received<T> with via saying which |
Iroh | the resource: id(), endpoint(), spawn(future) on the network runtime |
Voice, VideoFeed | with media: the microphone, a camera (VideoInput::camera()) or a screen (VideoInput::desktop()) on a shared entity, played and shown where the entity is. Below |
On the wire every message is signed by its author, and the body is opaque and length-prefixed
under a hashed kind, so a peer on an older build steps over what it does not know and keeps
working. Received data is treated as hostile: sizes are capped, unknown kinds are logged, and a
codec's verify runs before its decode.
media featurebevy_iroh = "0.5" # every feature but the browser ones, `wasm` and `web-demo`, is on by default
That includes demo, which gives cargo run in a checkout a window of its own (Bevy's
default plugins on Wayland and X11) so it can be the webcam example. An app that brings its
own Bevy can leave it off: default-features = false, features = ["ui", "webrtc", "v4l2", "desktop"].
Put Voice on a shared entity and your microphone goes to everyone in the room. A remote
entity that arrives with Voice is played back from where it is, relative to the camera that
carries AudioListener. VoiceLevel on both is a meter; Voice::muted is replicated so peers
can show it. Frames are 20 ms opus over QUIC datagrams on the same endpoint, with a jitter
buffer per track and concealment for what gossip would have retransmitted too late.
This is the beginning of the README. Read the rest at the original. Read the full README ↗