Coincidentally I'm seriously researching this topic so I cannot claim to have all the answers. Please correct me if I misunderstood part(s) of the ecosystem.
In short, the answer depends on the bigger picture of the project.
Personally I found it hard to actually understand the point and benefits of the RustxWebassembly ecosystem. It helps to keep in mind that your WASM code becomes a dynamic library. A self-contained "portable brain" that you plug into a platform.
So you have a plugin, but to make it dance you need platform interaction. Typically this interaction is glue code that knows about the platform capabilities and your WA interface.
Let's say you decide to write all code in Rust. This hasn't answered the actual question; how to structure the distinction between platform(/glue) code and app code. This post goes a bit into how to structure your code (with diagrams) and shortly describes the experience of each approach.
So, following the advice of the mentioned post, you could follow the first approach on your list; Use the WASM entry point to construct a canvas, WebGL context and register itself with window.requestAnimationFrame, without leaving Rust. This is possible through the bindings from web-sys.
Thankfully others have walked this path before; gate, raze rgx, which left lessons for us to learn.
But all the previous links are about engines and implementations of single-player games. The networking code should be considered in our evaluation! This is the point where I'm uncertain about a good approach.
The browser already has an event loop, so it's logical that our platform glue code handles threading and I/O; The browser will call into WASM when it's time to draw a frame or when socket data was received.
On the other side, there is this "ideal"(?) case where you "just" give a single thread to the, completely self-contained, WASM code and let it sort out everything itself. I/O or blanks are, according to this model, interrupts which preemptive/non-preemptive wake/schedule a rust future to perform the requested task. This is a literal brain analogy where sensory neurons are the interrupts.
I have no idea how feasible this idea actually is; I haven't found anyone else with a public source who did it like this. The WASM spec is also evolving still, I'm not familiar enough with the platform or spec direction to say this approach is supposedly supported.
I'm waiting for a blog post mentioning WASM+Async I/O that will come out next week which will shed some light onto the possibility of executors and rust futures in WASM (I hope).
Note that there is already a crate that abstracts "JS Promise" <-> "Rust Future". My initial impression of this crate was that it promotes platform event loops instead of WASM event loops, but the WASM+Async interview will definitely contain information about the direction of the WASM-team and possibilities.