{"id":15178458,"url":"https://github.com/giusdp/bevy_talks","last_synced_at":"2025-06-14T17:04:04.013Z","repository":{"id":110916244,"uuid":"592373165","full_name":"giusdp/bevy_talks","owner":"giusdp","description":"A Bevy plugin to write dialogues for your characters, together with player choices.","archived":false,"fork":false,"pushed_at":"2024-05-01T08:22:35.000Z","size":2486,"stargazers_count":60,"open_issues_count":6,"forks_count":6,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-03T19:46:23.898Z","etag":null,"topics":["bevy","dialogue-system","dialogues","gamedev","plugin","visual-novel","writing"],"latest_commit_sha":null,"homepage":"https://giusdp.github.io/bevy_talks/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/giusdp.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":"giusdp"}},"created_at":"2023-01-23T15:40:53.000Z","updated_at":"2025-02-16T04:05:43.000Z","dependencies_parsed_at":"2023-08-24T17:59:38.762Z","dependency_job_id":"523d343b-36c3-4b18-8ce2-bfa5e6848ba4","html_url":"https://github.com/giusdp/bevy_talks","commit_stats":null,"previous_names":["giusdp/bevy_screenplay"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/giusdp/bevy_talks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giusdp%2Fbevy_talks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giusdp%2Fbevy_talks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giusdp%2Fbevy_talks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giusdp%2Fbevy_talks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/giusdp","download_url":"https://codeload.github.com/giusdp/bevy_talks/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giusdp%2Fbevy_talks/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259716642,"owners_count":22900922,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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","dialogue-system","dialogues","gamedev","plugin","visual-novel","writing"],"created_at":"2024-09-27T15:03:26.648Z","updated_at":"2025-06-14T17:04:03.986Z","avatar_url":"https://github.com/giusdp.png","language":"Rust","funding_links":["https://github.com/sponsors/giusdp"],"categories":[],"sub_categories":[],"readme":"# Bevy Talks\n\n[![][img_bevy]][bevycrate] \n[![][img_license]][license] \n[![][img_tracking]][tracking] \n[![][img_version]][crates]\n[![][img_doc]][doc] \n[![][img_downloads]][crates]\n\n\u003e [!WARNING]  \n\u003e Be aware that `bevy_talks`'s API is still undergoing revisions (with possibly big architectural changes). Feedback on its ergonomics and developer experience (DX) is highly appreciated.\n\nThis [Bevy][bevy] plugin provides a way to create dialogues and conversations in your game as graphs. \n\nYou can imagine a *Talk* between the player and NPCs as a directed graph where each node is an *action* that can be performed \nsuch as saying a line, joining/leaving the conversation, or a choice the player can make.\n\nThe most common action is text being displayed on the screen, and a simple *Talk* is\njust a sequence of texts forming a conversation between actors.\n\nYou can have multiple entities each with their own *Talk* graph. Or you can make a VN-like game with one single big dialogue graph in the game.\n\n\u003e [!NOTE]\n\u003e A more in-depth documentation is being slowly written as an [mdbook here!](https://giusdp.github.io/bevy_talks/) Help is appreciated :)\n\n## Actions and Actors\n\nTalks are made up of actions that are translated into graph nodes. \nActions can be defined either via the `TalkBuilder` (where you have more control over the dialogue graph with custom components and events) or with \"talk.ron\" asset files. With the latter, you are building dialogue nodes by passing `Action` data:\n\n```rust\nstruct Action {\n    /// The ID of the action.\n    id: ActionId,\n    /// The kind of action.\n    action: NodeKind,\n    /// The actors involved in the action.\n    actors: Vec\u003cActorSlug\u003e,\n    /// Any choices that the user can make during the action.\n    choices: Option\u003cVec\u003cChoice\u003e\u003e,\n    /// The text of the action.\n    text: Option\u003cString\u003e,\n    /// The ID of the next action to perform.\n    next: Option\u003cActionId\u003e,\n}\n```\n\nIt contains several fields that define the kind of action it can be, the relevant actors, text or choices and the next action to perform (where to go in the graph after).\n\nThe actors are quite simple right now. It is just the name and an identifier (the slug):\n\n```rust\nstruct Actor {\n    /// The name of the actor.\n    name: String,\n    /// The unique slug of the actor.\n    slug: ActorSlug,\n}\n```\n\nHaving a well defined *Talk* with actions and actors will result in spawning a graph where all the nodes are entities.\nEach action will be an entity \"node\", and each actor is also an entity. \n\nAll the action nodes will be connected with each other with an aery relationship (called *FollowedBy*), following the graph structure given by the actions next and id fields, and each action with actors will result in the corresponding entity being connected with the actors entities with another aery relationship (called *PerformedBy*).\n\n\n## The Parent Talk\n\nAll the node entities in the graph will be a child of a main entity that represents the *Talk* itself, with the *Talk* component attached to it.\n\nYou can think of this parent Talk entity as it \"encapsulates\" the graph and you can use it to identify a dialogue graph. You will use it to send events to advance the dialogue.\n\n## Build Talks from talk.ron files\n\nThe above-mentioned ron assets files are used to create `TalkData` assets. They can be used to build dialogue graphs via bevy `Commands`. \n\nThe files must have the extension: `talk.ron`. Here's an example:\n\n```rust,ignore\n(\n    actors: [\n        ( slug: \"bob\", name: \"Bob\" ),\n        ( slug: \"alice\", name: \"Alice\" )\n    ],\n    script: [\n        ( id: 1, action: Talk, text: Some(\"Bob and Alice enter the room.\"), next: Some(2) ),\n        ( id: 2, action: Join, actors: [ \"bob\", \"alice\" ], next: Some(3)),\n        ( id: 3, actors: [\"bob\"], text: Some(\"Hello, Alice!\"), next: Some(4) ), // without the action field, it defaults to Talk\n        (\n            id: 4,\n            choices: Some([\n                ( text: \"Alice says hello back.\", next: 5 ),\n                ( text: \"Alice ignores Bob.\", next: 6 ),\n            ])\n        ),\n        ( id: 5, text: Some(\"Bob smiles.\"), next: Some(7)), // without the actors field, it defaults to an empty vector\n        ( id: 6, text: Some(\"Bob starts crying.\"), next: Some(7) ),\n        ( id: 7, text: Some(\"The end.\") ) // without the next, it is an end node\n    ]\n)\n```\n\nThe plugin adds an `AssetLoader` for these ron files, so it's as easy as: \n\n```rust\nlet handle: Handle\u003cTalkData\u003e = asset_server.load(\"simple.talk.ron\");\n```\n\nThen you can use `Talk::builder()` to create a `TalkBuilder`, which has the `fill_with_talk_data` method. \nYou can retrieve the `TalkData` from the assets collection `talks: Res\u003cAssets\u003cTalkData\u003e\u003e`.\n\nWith the builder ready, you can use the Commands extension to spawn the dialogue graph in the world:\n\n```rust\nuse bevy::prelude::*;\nuse bevy_talks::prelude::*;\n\n// We stored the previously loaded handle of a TalkData asset in this resource\n#[derive(Resource)]\nstruct TalkAsset {\n    handle: Handle\u003cTalkData\u003e,\n}\n\nfn spawn(mut commands: Commands, talks: Res\u003cAssets\u003cTalkData\u003e\u003e, talk_asset: Res\u003cTalkAsset\u003e) {\n    let talk = talks.get(\u0026talk_asset.handle).unwrap();\n    let talk_builder = TalkBuilder::default().fill_with_talk_data(simple_talk);\n\n    // spawn the talk graph\n    commands.spawn_talk(talk_builder, ());\n}\n```\n\nSpawning that talk graph will result in this:\n\n```mermaid\ngraph LR;\n    A[Narrator Talks] --\u003e B[Alice,Bob Join];\n    B --\u003e C[Bob Talks];\n    C --\u003e D[Choice];\n    D --\u003e E[Narrator Talks];\n    D --\u003e F[Narrator Talks];\n    F --\u003e G[Narrator Talks];\n    E --\u003e G;\n```\n\n## Usage\n\nBesides building dialogue graphs, at some point you have to interact with them. \nAfter all the nodes are entities with components, so you could just do queries using the special `CurrentNode` component that keeps track of the current node. Then each node could have a `TextNode`, `JoinNode`, `LeaveNode`, `ChoiceNode` or your own custom components (added via the builder). \n\nAnother way is to use a dialogue graph in an event-driven way. The plugin sends events every time you move to a new node based on the components it has. A node with a `TextNode` will send a `TextNodeEvent` event, a node with a `ChoiceNode` will send a `ChoiceEvent` event, and so on. You can also add your own node emitting components to customize the behaviour.\n\nFor example, to display the text of a `TextNode` you can simply listen to the `TextNodeEvent` event:\n\n```rust\nfn print_text(mut text_events: EventReader\u003cTextNodeEvent\u003e) {\n    for txt_ev in text_events.read() {\n        let mut speaker = \"Narrator\";\n        println!(\"{}\", txt_ev.text);\n    }\n}\n```\nNote that the actors connected to the node are injected in the event, so you don't need to query them.\n\n### Request Events\n\nThat's the events from a dialogue graph to you. There is also the other direction so you can send requests to the dialogue graph (to advance the dialogue).\n\nTo move forward to the next action:\n\n```rust\n/// Event to request the next node in a `Talk`.\n/// It requires an entity with the `Talk` component you want to update.\n#[derive(Event)]\npub struct NextNodeRequest  {\n    /// The entity with the `Talk` component you want to update.\n    pub talk: Entity,\n}\n```\n\nTo jump to a specific action (used with choices):\n\n```rust\n/// An event to jump to some specific node in a graph. \n/// It requires an entity with the `Talk` component you want to update.\n#[derive(Event)]\npub struct ChooseNodeRequest {\n    /// The entity with the `Talk` component you want to update.\n    pub talk: Entity,\n    /// The next entity to go to.\n    pub next: Entity,\n}\n```\n\nThere is also an useful event to re-send all the events associated to a node:\n\n```rust\n/// Event to request the current node to re-send all its events.\n#[derive(Event)]\npub struct RefireNodeRequest {\n    /// The entity with the `Talk` component you want to update.\n    pub talk: Entity,\n}\n```\n\nYou pass the entity with the `Talk` component in these events, plus the next node entity in case of the choose event.\n\nCheck out the `examples` folder to see how to use the plugin.\n\n- [simple.rs](examples/simple.rs) shows how to use the plugin to create a simple, linear conversation. \n- [choices.rs](examples/choices.rs) shows how to use the plugin to create a conversation with choices (jumps in the graph).\n- [full.rs](examples/full.rs) shows a Talk where all the action kinds are used.\n- [ingame.rs](examples/ingame.rs) shows how to use the plugin with more than one talk you can interact with.\n- [custom_node_event.rs](examples/custom_node_event.rs) shows how to add your own event emitting component to create a custom node.\n\n### Roadmap\n\nSome nice-to-haves from the top of my head:\n\n- [x] More node kinds (got rid of node kinds, now nodes are entities with components)\n- [x] Extensive documentation/manual wiki (added an mdbook, but always in progress...)\n- [x] Extensible Interaction/Trigger system (I mean I'm using events, more decoupled than this is impossible)\n- [ ] Use the built-in bevy_ecs relations (when one day when we will have them)\n- [ ] Dialogue UIs \n- [ ] Graphical editor to create the asset files\n- [ ] Voice lines/sound support\n- [ ] Support other asset formats (yarn?)\n- [ ] More examples\n- [ ] Localization with [Fluent](https://projectfluent.org/)\n\n### Bevy Version Support\n\nCompatibility of `bevy_talks` versions:\n| `bevy_talks` | `bevy` |\n| :--                 |  :--   |\n| `main`              | `0.12`  |\n| `0.5.0`              | `0.12`  |\n| `0.4.0`              | `0.12`  |\n| `0.3.1`              | `0.12`  |\n| `0.3.0`              | `0.11`  |\n| `0.2.0`              | `0.11`  |\n| `0.1.1`              | `0.11`  |\n| `bevy_main`              | `main`  |\n\n## License\n\nDual-licensed under either of\n\n- Apache License, Version 2.0, ([LICENSE-APACHE](/LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0)\n- MIT license ([LICENSE-MIT](/LICENSE-MIT) or https://opensource.org/licenses/MIT)\n\nat your option.\n\n## Contribution\n\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any\nadditional terms or conditions.\n\n[bevy]: https://bevyengine.org/\n[renpy]: https://www.renpy.org/\n\n[img_bevy]: https://img.shields.io/badge/Bevy-0.12.1-blue\n[img_version]: https://img.shields.io/crates/v/bevy_talks.svg\n[img_doc]: https://docs.rs/bevy_talks/badge.svg\n[img_license]: https://img.shields.io/badge/license-MIT%2FApache-blue.svg\n[img_downloads]:https://img.shields.io/crates/d/bevy_talks.svg\n[img_tracking]: https://img.shields.io/badge/Bevy%20tracking-released%20version-lightblue\n\n[bevycrate]: https://crates.io/crates/bevy/0.12.1\n[crates]: https://crates.io/crates/bevy_talks\n[doc]: https://docs.rs/bevy_talks/\n[license]: https://github.com/giusdp/bevy_talks#license\n[tracking]: https://bevyengine.org/learn/book/plugin-development/#main-branch-tracking\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgiusdp%2Fbevy_talks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgiusdp%2Fbevy_talks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgiusdp%2Fbevy_talks/lists"}