Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

web assembly module target (wasm interface) to replace bondage.js #213

Open
blurymind opened this issue Aug 30, 2024 · 14 comments
Open

web assembly module target (wasm interface) to replace bondage.js #213

blurymind opened this issue Aug 30, 2024 · 14 comments

Comments

@blurymind
Copy link

blurymind commented Aug 30, 2024

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

@blurymind blurymind changed the title web assembly module target (wasm interface) web assembly module target (wasm interface) to replace bondage.js Aug 30, 2024
@janhohenheim
Copy link
Member

Sounds like a great idea! I'd welcome any PRs that would help with this :)

@blurymind
Copy link
Author

blurymind commented Aug 30, 2024

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

@janhohenheim
Copy link
Member

Since this would be useful to anyone using Yarn Spinner in the web, I'm fine with adding a new crate right here :)

@blurymind
Copy link
Author

blurymind commented Aug 30, 2024

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"),

@janhohenheim
Copy link
Member

janhohenheim commented Aug 30, 2024

@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 :)

@blurymind
Copy link
Author

blurymind commented Sep 2, 2024

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

@janhohenheim
Copy link
Member

janhohenheim commented Sep 2, 2024

@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.

@blurymind
Copy link
Author

@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

@janhohenheim
Copy link
Member

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 :)

@blurymind
Copy link
Author

blurymind commented Sep 3, 2024

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()
    }
    ///////////////////////////////

@blurymind
Copy link
Author

blurymind commented Sep 5, 2024

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

@janhohenheim
Copy link
Member

@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.

@blurymind
Copy link
Author

Thank you 🙇 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

@janhohenheim
Copy link
Member

Alright, I've got some more time now. @blurymind, mind telling me what you're currently stuck with?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants