Giter Site home page Giter Site logo

liamgallagher737 / learnbevy Goto Github PK

View Code? Open in Web Editor NEW
20.0 3.0 0.0 39.27 MB

An online web app for playing around with Bevy in the browser (unofficial)

Home Page: https://learnbevy.com/playground

License: Apache License 2.0

Dockerfile 0.70% Shell 0.59% Rust 14.36% JavaScript 2.93% CSS 0.58% TypeScript 39.31% HTML 0.13% Svelte 20.72% WGSL 16.99% GLSL 1.19% Nix 2.50%
bevy rust sveltekit

learnbevy's Introduction

Bevy Playground (for now)

An online web app for playing around with Bevy in the browser.

Why is it called learnbevy?

The end goal is to build challenge like tutorials for learning different aspects of the Bevy game engine. An example of one could be learning how to use run conditions. Currently the focus is on building a user friendly and featureful playground that will then be used for the challenges.

Here is a list of current and planned features

  • Code editor with syntax highlighting (highlight is stolen from the rust playground)
  • Visual window
  • Console that displays logs and build stderr
  • Selectable Bevy version and rust channel (nightly and stable)
  • Formatting code
  • Sharing code
  • Bevy example selector
  • Assets for testing with
  • Popular crates
  • Entity hierarchy
  • Entity inspector
  • Rust analyzer running in the browser (it's possible)

πŸ“‚ compile_api

This is the program than compiles the code to wasm.

How it works

Each request spins up a new podman container, see images for for infomation on them.

The http server in use is tide, I chose this due to its middleware which works quite well for this use case. Each stage is implmented as its own middleware.

To keep the service avaliable for everyone to use there is rate limiting which adds a 5 second deplay before another request can be made when the last one was successful but only 1 second if it was unsuccessful. There is also what I call "ip locking" which allows only a single concurrent request from each IP address.

Hosting

Currently it is running on a single 7950 VDS 1 from HostENOS in Salt Lake City. I chose this due to it's great single threaded performance which seems to be the most important for incrimental builds.

Metrics / Uptime

The server collects metrics about the number of requests, their statuses and how long they take. A public grafana dashboard is avaliable to view at https://metrics.learnbevy.com. I also have uptime messuarements using Better Stack, the public status page can be found at https://status.learnbevy.com.

Local Development

All the program needs to run is podman and the images for the versions and channels you want to use/test.

You can pull them like this.

podman pull ghcr.io/liamgallagher737/learnbevy-<version>-<channel>
podman pull ghcr.io/liamgallagher737/learnbevy-0.14-nightly # 0.14 on nightly
podman pull ghcr.io/liamgallagher737/learnbevy-main-stable # bevy main branch on stable

If you want to build them yourselve see the images section.

πŸ“‚ compile_server_os

This is the NixOS system config for the server(s) running the compile_api program.

You can install NixOS with the config on any achine you have root ssh access to using the following command.

nix run github:nix-community/nixos-anywhere -- --flake .#<server-type> root@<ip address>

The server-type is any of the outs from flake.nix. This is because parts of the config will depend on the server they are running on.

Once installed, any updates to the config can be activated by running the following command on the server via ssh.

nixos-rebuild switch --flake <URI to your flake>

Or if your cool and use NixOS you can rebuild it without needing to ssh into it with this command.

nixos-rebuild switch --flake .#<server-type> --target-host "root@<ip address>"

πŸ“‚ images

This is where the Dockfile is for the images used durning compiling. A single dockerfile is used taking both a Bevy version and Rust channel as arguments. The Cargo.toml files for each version are in the manifests directory, each version gets it's own file as the features change between versions.

Building

An image can be build like this, replace 0.14 and stable with options of your choice.

podman build --build-arg="version=0.14" --build-arg="channel=stable" --tag "ghcr.io/liamgallagher737/learnbevy-0.14-stable" .

πŸ“‚ rustfmt_api

This is the program that formats the code.

How it works

This is a very simple server using warp, just a single main.rs file. Each requests runs a new rustfmt process and pipes the users code into stdin. The formatted code is then read through stdout.

Hosting

There are three instances of this server running on fly.io's free tier. The machines being used are shared-cpu-1x@256MB as that is the maximum to stay in the free their while keeping them permanently up which is ideal to avoid cold starts. The three instances run in the following regions.

  • Dallas, Texas πŸ‡ΊπŸ‡Έ
  • Sydney, Australia πŸ‡¦πŸ‡Ί
  • Amsterdam, Netherlands πŸ‡³πŸ‡±

πŸ“‚ www

This is the website https://learnbevy.com.

How it works

It is a SvelteKit 4 app that uses tailwind for styling and shancn-svelte for the ui components.

Hosting

The website is hosted on Cloudflare Pages for free. The shares are stored in a Cloudlflare KV database which is also free.

The program can be built with the following command

Local Development

Most of the time a simple npm run dev will suffice however if you want to use the sharing functionality you will have to build the app and run it with wrangler, this is due to needing a database. The following command will do both.

npm run build && npx wrangler pages dev .svelte-kit/cloudflare

If you want the website to use a locally running compile server you can specify a url in your .env file.

PUBLIC_COMPILE_HOST=http://localhost:53740

If your running the compile server with ssl then most likely your browser will block the request when you try to compile due to an untrusted self-signed certificate. To trust it on Firefox you can go to https://localhost:53740/compile and click on the Advanced then Accept the Risk. Other browser should be very simular.

βš–οΈ License

All code in this repository is dual-licensed under either of the following license at your option.

The assets included in this repository are copied from the Bevy repository and typically fall under different open licenses. See CREDITS.md for the details of the licenses of those files.

learnbevy's People

Contributors

liamgallagher737 avatar learnbevy-crate-updates[bot] avatar dependabot[bot] avatar

Stargazers

 avatar Miguel Medina Ballesteros avatar Rob Parrett avatar 1D3D4RY avatar Victor Bjelkholm avatar  avatar momokinou avatar Marc Ferraro avatar Ajith avatar Law avatar  avatar Adam avatar Cooper Jax Reiff avatar Hector Crean avatar Charlie El Kabbouchi avatar Sebastien Menozzi avatar Per Johansson avatar  avatar  avatar Georges KABBOUCHI avatar

Watchers

 avatar  avatar  avatar

learnbevy's Issues

Use NixOS for the compile server(s)

Currently configuring the server is a pain and can only really be done by me. It would be nice to have an easily distributional configuration for when I add more compile servers too.

I have liked using NixOS as my personal OS and think it will be a great solution for this problem.

Add the Bevy main branch as a version

It would be nice to be able to experiment with Bevy's main branch in the playground. The latest release of Bevy would still remain the default.

Implementation

Building the images

The most sensible approach in my mind is to copy the rust-playground's way of building images each night (Their GitHub workflow, Official Example). The image would be uploaded to docker hub or ghcr and pulled on the compiler server(s).

Pulling the images

I think the simplest way to pull the images is to have the server(s) poll docker hub or gchr for updates every few minutes for updates. If you have any other ideas please share.

Caching

Need to make sure caching is disabled for main branch builds or give it a short TTL, eg. 1 hour.

Sharing

When a user shares a playground running on the main branch it should also store store the commit hash or some other identifier. This means when the user or someone else opens the share after 24 hours it can show a alert that the code may be broken due to being from an older version.

Something like this.
image

Extra

Ideally make it in a way that #8 doesn't require it to be rewritten much.

Add drop down for selecting offical Bevy examples

Add useful addition would be a drop down to select from official example like on https://go.dev/play/.

image

Implementation

This would depend on #5 adding all the same assets the Bevy examples use.

Ui

Using shadcn's combobox would be the best fit due to having a search box and there being a lot of examples.

Getting examples

Using the GitHub api to get repo contents and then recursively finding all the examples seems like the easiest way to me without making it to manual.

Getting the examples themselves would just be a case of filling in the following url.

https://raw.githubusercontent.com/bevyengine/bevy/release-[VERSION]/examples/[EXAMPLE_PATH]

Code is poorly documented

While the readme has a pretty good overview of what each part does, the code itself is poorly documented.

Improve devenv setup

Currently using podman also requires having virtualisation.containers.enable = true; in the users nixos config, it would be better if this was apart of the local setup or at least documented.

Only applies to those using NixOS and devenv.

Components depending on settings store renderer unnecessarily

When opening the settings popup it sets the value of the settings store which causes the examples drop down and crates list panel to renderer even though the value hasn't changed. This can be seen by opening the crates lists panel and then opening the settings popup, the crates list panel will enter the loading state for a split second.

Add examples from 3rd party crates

Feature

It would be good to have examples from the available 3rd party crates in the examples search menu. For example, bevy_mod_picking is available in the playground so we would include its examples.

Solution

The best approach I can thing of ks just to copy/reuse the example loading for the main branch as most crates have version tags for their repo in the same way Bevy does.

These examples would then be added to the bottom of the list prepended by a <create-name>/.

Add LICENSE.md

This is incredibly neat, and I'd like to eventually use this as a reference for a first-party version.

To do so safely though, this project needs to have an explicit open source license :) MIT, Apache or MIT + Apache would be ideal. but any permissive license would do.

Add assets for use in the playground

As far as I can tell, Bevy cannot load assets from other domains and they must be under they /assets path on the site. Not being able to use assets in the playground is very limiting so it makes sense to add some that can be used. There should also be somewhere in the editor to get the urls for these so users don't have to reference the github for them.

Entity Inspector

A way to view the entity hierarchy and components would be very useful for a learning / experimenting tool like this.

How

I previously started working working on this but decided to focus on improving the current state of the playground rather than adding heaps of features. The work can be found on the entity-inspector branch.

This approach was to store a pointer to the Bevy world and have a get_entities method which could be called from js. The following is the extra Rust that would be added before compiling.

static __WORLD_PTR: std::sync::OnceLock::<usize> = std::sync::OnceLock::new();
#[wasm_bindgen::prelude::wasm_bindgen]
pub unsafe fn __get_entities() -> wasm_bindgen::JsValue {
let ptr_usize = __WORLD_PTR.get().unwrap();
let ptr = *ptr_usize as *const bevy::ecs::world::World;
let world = ptr.as_ref().unwrap();
let map = js_sys::Map::new();
for entity in world.iter_entities() {
let id = entity.id();
let components_info = world.inspect_entity(id);
let len = components_info.len() as u32;
let component_names = js_sys::Array::new_with_length(len);
for n in 0..len {
let js_name = wasm_bindgen::JsValue::from_str(components_info[n as usize].name());
component_names.set(n, js_name);
}
map.set(&wasm_bindgen::JsValue::from_str(&format!("{id:?}")), &wasm_bindgen::JsValue::from(component_names));
}
wasm_bindgen::JsValue::from(map)
}
fn __set_world_ptr(world: &bevy::ecs::world::World) {
let _ = __WORLD_PTR.set(world as *const bevy::ecs::world::World as usize);
}
#[derive(Debug)]
#[wasm_bindgen::prelude::wasm_bindgen(getter_with_clone)]
pub struct __EntityInfo {
#[wasm_bindgen(readonly)]
pub index: u32,
#[wasm_bindgen(readonly)]
pub generation: u32,
#[wasm_bindgen(readonly)]
pub component_names: wasm_bindgen::JsValue,
}"#;

For accessing the components we would just use Bevy reflect in a similar way to how I get the entities in the code snippet above.

Visuals (thoughts wanted)

I am unsure of the best way to display the inspector / hierarchy in the playground. It should defiantly be toggleable to avoid taking space when not needed.

Add a logo

Currently the favicon is just the svelte logo, a custom one would be nice.

Collect metrics from compile_api

Currently the only data kept about how well the server is running is the logs which say how long each request took. This could be greatly improved by adding proper metrics.

How

My preferred way would be to host a Prometheus compatible endpoint to be scraped. This article shows an example of this.

Build fails when app does not chain methods for setup

If an app does not use chaining to setup their app the __check_exit_flag breaks it.

Steps to replicate (share)

  1. Open the "Stress Tests / Many Gizmos" example in the playground
  2. Remove line 83 as it contains include_str!
  3. Build

Full Output

   Compiling game v0.1.0 (/playground)
warning: variable does not need to be mutable
  --> src/main.rs:15:9
   |
15 |     let mut app = App::new().add_systems(Update, __check_exit_flag);
   |         ----^^^
   |         |
   |         help: remove this `mut`
   |
   = note: `#[warn(unused_mut)]` on by default

error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:15:19
   |
15 |     let mut app = App::new().add_systems(Update, __check_exit_flag);
   |                   ^^^^^^^^^^                                       - temporary value is freed at the end of this statement
   |                   |
   |                   creates a temporary value which is freed while still in use
16 |     app.add_plugins((
   |     --- borrow later used here
   |
help: consider using a `let` binding to create a longer lived value
   |
15 ~     let binding = App::new();
16 ~     let mut app = binding.add_systems(Update, __check_exit_flag);
   |

For more information about this error, try `rustc --explain E0716`.
warning: `game` (bin "game") generated 1 warning
error: could not compile `game` (bin "game") due to 1 previous error; 1 warning emitted

Automatic 3rd party crate version crawling

Feature

All of the crates currently available have a Bevy support table, it would be great to have a github action that scans these every day or so and creates a pull request or issue to update it for the correct Bevy version.

Implementation

The following steps show how this could be done

  • Fetch the crate's data with https://crates.io/api/v1/crates/<name>(example)
  • Get the readme url from the version at index 0
    image
  • Fetch the readme with the url from the previous fetch (example)
  • Parse the html for a table where a header <th> has the value bevy or similar (eg. bevy_kira_audio uses Bevy version)
  • Figure out which column is for Bevy, most are the first column but some like bevy_hanabi have it swapped
  • Parse the table and use the latest version when multiple are listed
  • If the version is a semver range (eg. 0.14 and not 0.14.1) then check the crates.io response from the first request and match the latest one to the semver pattern
    image

Example of bevy_dev

<table>
  <thead>
    <tr>
      <th>bevy</th> <!-- look for this - bevy is first column-->
      <th>bevy_dev</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0.13.2</td> <!-- bevy version -->
      <td>0.3 - 0.3.1</td> <!-- multiple versions - use latest -->
    </tr>
    <tr>
      <td>0.13.0</td>
      <td>0.2</td>
    </tr>
    <tr>
      <td>0.12.1</td>
      <td>0.1 - 0.1.1</td>
    </tr>
  </tbody>
</table>

Playing fails

Problem

Some users are unable to compile and play a playground unless they are in incognito/private browsing mode while others can't compile at all.

The request goes through and gets a 200 response but fails with net::ERR_FAILED.

image
From Ziven on Discord

Affected Users Details

Chrome 125.0.6422.142 (Official Build) (64-bit)

Incognito works but normal browser doesn't even after clearing cache and disabling extensions.

Safari 17.5 (19618.2.12.11.6) on MacOS 14.5 with M1 Max

Doesn't work in normal browsing or private browsing. It does work on Chrome at their work (different computer).

Extra information

Discord thread: https://discord.com/channels/691052431525675048/1246951183059517563

Add popular Bevy crates

Having some popular creates available in the same way the rust playground does would make the playground a lot more useful. All the crates used in the official Bevy examples should also be available.

Keeping builds fast

The rust playground will remove the dependencies if they are not used, however as far as I can tell they either have none or all. I don't think it would be to difficult to figure out what crates are being used by analyzing the code and toggle each dependency individually. Testing should be done to find whether this would make a difference.

Automatic updating

It's unrealistic manually update the images when each crate updates. The way the rust playground solves this is by building the images on a schedule each day. In our case this would mean building the images on a schedule every 24 hours and uploading the images to docker hub then pulling them on the bevy_compile_api server(s).

Problem

The playground allows for multiple versions of Bevy to be used. Most crates target the latest version of Bevy so if the crates updated each nigh once a version is no longer the latest it will very likely become incompatible with the crates.

A possible solution is to only update crates for the latest version of Bevy and lock the older versions to the last version when Bevy updated. This would also have the positive effect of only having to update the latest version each night, saving on compute and time.

One thing that needs to be addressed is the process when a new Bevy version comes out. Some crates will be update to support the latest version before the playground so we would need to make sure these quickly updated crates don't get added for the previous version.

Crates (thoughts wanted part)

The list of crates to be added, please comment if you think of a good addition. I don't want to have too many.

*included in official Bevy examples

feat: collaborative editor (multiplayer)

Reason

I've noticed people on the discord like to use the playground for helping others debug and fix their code. Having a collaborative environment would improve the experience for this use case.

Implementation

My idea for the implementation of this is to have another web server that's hosts "rooms" that users can connect to with a unique ID that the host will get when they create a room. Users will then communicate with this server over a web socket.

The warp framework seems to have good web socket support so I'd likely go with it for the server.

There is a good article on how to implement collaboration with a Monaco editor that we could use as a reference to build the front end in, live cursors and stuff.

Improve local development for bevy_compile_api

Currently when developing bevy_compile_api locally I have to comment out and change a bunch of things including

  • Swap TlsListener for plain http
  • Swap the CF ip header for peer_addr
  • Change log and cache paths

Solution

To make this easier one solution would be to have a "local" feature what toggles these things with cfg attributes.

Preflight requests are send before every compile request

Instead of caching the options response, the browser will send a new request before every compile. In the case of me in New Zealand this adds a lot of extra latency. I did not see the same issues on Microsoft Edge, only Firefox.

image

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.