Open blurymind opened 2 months ago
Sounds like a great idea! I'd welcome any PRs that would help with this :)
should it be a PR to this repository or should it be another repository which uses this module as a dependency?
I've been thinking of giving it a try by exposing things via wasm_bindgen, with the output going to a pkg folder.
Guess it will be a lib.rs file and a new output folder? It would add a bunch of new dependencies for sure
Since this would be useful to anyone using Yarn Spinner in the web, I'm fine with adding a new crate right here :)
Ok I will give this a stab in the weekend. Do you have an example where using its api, you initialise it from the raw string data of the yarn file? Since its a web module, we have no file access, that needs to be done by the browser instead.
Would be helpful to also get the variable state and write to it - exposing that is needed for game persistence (load/save states)
guessing I can just do this?
YarnSpinnerPlugin::with_yarn_source("yarn data here"),
@blurymind I thought a bit about it. Since Bevy can run completely headless, you don't need an iframe at all to run the Bevy app. Simply communicate with it over wasm-bindgen
exposed functions that e.g. trigger an observe on Bevy's side. I think that's the simplest solution.
I have not used wasm-bindgen
in ages, so you know more about that than I do. But let me know if you need help with any Bevy-related things :)
Do you have an example where using its api, you initialise it from the raw string data of the yarn file?
No, but it should be as you guessed:
let content = "
title: Foo
---
Narrator: Hello world!
===
"
let file = YarnFile::new("my_file.yarn", content);
let plugin = YarnSpinnerPlugin::with_yarn_sources([
YarnFileSource::InMemory(file)
]);
Note that you can also initialize the plugin with deferred
to start the app without knowing your yarn files yet. You can then send a LoadYarnProjectEvent
at runtime when the content is ready.
Would be helpful to also get the variable state and write to it - exposing that is needed for game persistence (load/save states)
DialogueRunner::variable_storage
and its _mut
variant do exactly that :)
thank you for the guidance. To be fair I am still learning rust, so it might take me some time to get something going, but i really want this feature for my other projects.
One thing that is a concern is pulling bevy stuff with the library. In my case I want the tiniest possible web module size - so if it pulls the bevy stuff and end up being 70+ mb, it probably wont be accepted in gdevelop.
The ideal output really is to bundle only whats needed to parse the yarn file and get an instance that outputs text, options or commands depending on how you interact with it. Basically the tiniest size possible :)
I am guessing this is what i want https://github.com/YarnSpinnerTool/YarnSpinner-Rust/blob/main/crates/yarnspinner/src/lib.rs the comment says that it can be used standalone, so should be my target to expose it?
I sort of wonder if I still need some sort of a bridge class on the rust side or the js side . Surely wont be as simple as slapping a bunch of annotations
@blurymind when compiling for size, using wasm-opt
and gzipping the result, Bevy is around 5 MiB big.
But you can certainly use the non-Bevy version standalone, yes :) There is a demo of a TUI written with just that.
I don't know whether we can expose the structs directly or we need to wrap them first. If you can annotate them and they're usable that way in JS, I'm happy to merge that.
@janhohenheim this is the demo right? https://github.com/YarnSpinnerTool/YarnSpinner-Rust/blob/main/examples%2Fyarnspinner_without_bevy%2Fsrc%2Flib.rs
seems like a better starting point for my use case. Just hope i dont run into errors because of some dependency not being supported by wasm
I have a running Wasm demo of the Yarn Spinner for Bevy code at https://janhohenheim.itch.io/yarnspinner-rust-demo, which is a superset of the Yarn Spinner for Rust standalone code. This means I can confirm that all dependencies support Wasm :)
I am actually getting this error
Error: error: extraneous input '\n ' expecting {ID, '#'}
I think its because the content string has new lines?
this made it work
let content = "title: Foo
---
Narrator: Hello world!
===
".to_string()
yay! I can load the file from a string now :D progress lol
I added this thing to compilers.rs to do it with the hello_world demo
/// //////////////////////
pub fn try_read_from_content(&mut self, file_name: String, file_content: &String) -> std::io::Result<&mut Self> {
self.files.push(File {
file_name,
source: file_content.to_string(),
});
Ok(self)
}
pub fn read_content(&mut self, file_name: String, file_content: &String) -> &mut Self {
self.try_read_from_content(file_name, &file_content).unwrap()
}
///////////////////////////////
I am now trying to make a version of the hello_world demo that is a wasm module. I had a successful test of this on a fresh project here https://github.com/blurymind/wasm-module
[lib]
crate-type=["cdylib"]
and run
wasm-pack build --target web
attempting the same on this one doesnt quite work. The compilation fails.
I think I am not structuring it right and setting build targets at the correct level. I need to learn more about how these cargo.toml files are configured before attempting to fit my basic wasm test with this project :)
I am not sure what folder my module should live in and if it needs to be added to an existing cargo.toml file as a target - or if a new one needs to be made. Just getting it to compile is now my target
@blurymind I can take look over the next days. If you want something easier to setup for now, Bevy runs on Wasm out of the box, so you could tinker with that a bit to get your feet wet :) See the demo project in the repo.
Thank you :bow: sorry I have a long way to go with rust. Would be amazing to give yarn classic a proper support for yarn spinner. I've wanted to do that for years now
Alright, I've got some more time now. @blurymind, mind telling me what you're currently stuck with?
I guess my general question is how to even begin with getting this to compile with my modifications to expose anything to wasm? Should I create another module folder somewhere and should i use wasm-bindgen with wasm-pack build --target web ? try to make something that replicates what the cli example does, but as a library? When I tried to do it directly on the cli example, I ran into compilation errors with dependencies not having web target
The current (classic) editor for yarn files (https://github.com/blurymind/YarnClassic) uses bondagejs (https://github.com/hylyh/bondage.js) which is an alternative to yarn spinner. It is unfortunately not a very active project, which doesnt support yarn spec version 2.
I wonder if I can replace it with the rust port of yarn spinner - running as a web module. But in order for that to work it needs an interface to be used as a web module. It needs to take input data (string - the actual file reading will be done by the web browser), it needs to receive commands to advance dialog or select options, it needs to trigger browser events or callback functions with the output - so that is then displayed on the website or web app. The goal here is to be able to compile to a minimal size target no dependencies web module that can be used with any html5 game engine.
I wonder how much would it increase the bundle size of the app and if an alternative is to just create a bevy player instead of a full on wasm interface and just iframe it in the app. Thats not ideal of course
I also created the yarn wrapper in https://github.com/4ian/GDevelop https://wiki.gdevelop.io/gdevelop5/all-features/dialogue-tree/ that also currently uses bondagejs and as a result yarn syntax support in gdevelop is not great. It's another project that can benefit from this and I can make a PR to if its doable