kitgit

tirbofish/dropbear · commit

8d5b3f3172fbf6054ef3053d5ffc3274c9aafbe8

changing from wasmer to boa_engine and using gleam

Unverified

tk <4tkbytes@pm.me> · 2025-09-16 09:44

view full diff

diff --git a/Cargo.toml b/Cargo.toml
index 43311b3..1a9efc7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -42,8 +42,8 @@ open = "5"
 parking_lot = {version = "0.12", features = ["deadlock_detection"] }
 rfd = "0.15.4"
 ron = "0.11"
-russimp-ng = { version = "3.2", features = ["static-link"] }
-rustyscript = { version = "0.12" }
+# russimp-ng = { version = "3.2", features = ["static-link"] }
+# rustyscript = { version = "0.12" }
 serde = { version = "1.0.219", features = ["derive"] }
 spin_sleep = "1.3"
 transform-gizmo-egui = { git = "https://github.com/4tkbytes/transform-gizmo"}
@@ -52,13 +52,15 @@ wgpu = "26"
 winit = { version = "0.30", features = [] }
 zip = "5.1"
 walkdir = "2.3"
-wasmer = { version = "6.1.0-rc.3" }
+# wasmer = { version = "6.1.0-rc.3" }
 rayon = "1.11"
 flate2 = "1.1"
 reqwest = { version = "0.11", features = ["stream"] }
 tar = "0.4"
 async-trait = "0.1"
 futures-util = "0.3"
+boa_engine = "0.20"
+
 
 gltf = "1"
 thiserror = "2.0"
@@ -77,11 +79,11 @@ lto = false
 # it takes way too long to exit out
 panic = "abort"
 
-[profile.release]
-opt-level = 3
-lto = true 
-codegen-units = 1
-strip = true
-panic = "abort"
-debug = false
-incremental = false
+# [profile.release]
+# opt-level = 3
+# lto = true 
+# codegen-units = 1
+# strip = true
+# panic = "abort"
+# debug = false
+# incremental = false
diff --git a/eucalyptus-core/Cargo.toml b/eucalyptus-core/Cargo.toml
index 93f73e1..36ffd02 100644
--- a/eucalyptus-core/Cargo.toml
+++ b/eucalyptus-core/Cargo.toml
@@ -24,7 +24,7 @@ parking_lot.workspace = true
 ron.workspace = true
 serde.workspace = true
 winit.workspace = true
-wasmer.workspace = true
+# wasmer.workspace = true
 lazy_static.workspace = true
 rayon.workspace = true
 reqwest.workspace = true
@@ -33,6 +33,7 @@ tar.workspace = true
 zip.workspace = true
 tokio.workspace = true
 futures-util.workspace = true
+boa_engine.workspace = true
 
 [dev-dependencies]
 pollster = "*"
diff --git a/eucalyptus-core/src/dropbear.rs b/eucalyptus-core/src/dropbear.rs
new file mode 100644
index 0000000..8b9ef0a
--- /dev/null
+++ b/eucalyptus-core/src/dropbear.rs
@@ -0,0 +1 @@
+//! A module used for exposing functions
\ No newline at end of file
diff --git a/eucalyptus-core/src/input.rs b/eucalyptus-core/src/input.rs
index 52aa21b..130c946 100644
--- a/eucalyptus-core/src/input.rs
+++ b/eucalyptus-core/src/input.rs
@@ -3,10 +3,9 @@ use std::{
     time::{Duration, Instant},
 };
 
-use wasmer::{Function, FunctionEnvMut};
 use winit::{event::MouseButton, keyboard::KeyCode, platform::scancode::PhysicalKeyExtScancode};
 
-use crate::scripting::{DropbearScriptingAPIContext, ScriptableModuleWithEnv};
+use crate::scripting::{DropbearScriptingAPIContext};
 
 #[derive(Clone)]
 pub struct InputState {
@@ -49,42 +48,4 @@ impl InputState {
     pub fn is_key_pressed(&self, key: KeyCode) -> bool {
         self.pressed_keys.contains(&key)
     }
-}
-
-impl ScriptableModuleWithEnv for InputState {
-    type T = DropbearScriptingAPIContext;
-
-    fn register(env: &wasmer::FunctionEnv<Self::T>, imports: &mut wasmer::Imports, store: &mut wasmer::Store) -> anyhow::Result<()> {
-        fn is_key_pressed_impl(env: FunctionEnvMut<DropbearScriptingAPIContext>, key_code: u32) -> u32 {
-            if let Some(input) = env.data().get_input() {
-                match KeyCode::from_scancode(key_code) {
-                    winit::keyboard::PhysicalKey::Code(key_code) => {
-                        if input.is_key_pressed(key_code) { 1 } else { 0 }
-                    },
-                    winit::keyboard::PhysicalKey::Unidentified(_) => 0,
-                }
-            } else {
-                0
-            }
-        }
-        let is_key_pressed = Function::new_typed_with_env(store, &env, is_key_pressed_impl);
-
-        fn get_mouse_position_impl(env: FunctionEnvMut<DropbearScriptingAPIContext>) -> (f64, f64) {
-            if let Some(input) = env.data().get_input() {
-                input.mouse_pos
-            } else {
-                (0.0, 0.0)
-            }
-        }
-        let get_mouse_position = Function::new_typed_with_env(store, &env, get_mouse_position_impl);
-
-        imports.define(Self::module_name(), "getMousePosition", get_mouse_position);
-        imports.define(Self::module_name(), "isKeyPressed", is_key_pressed);
-
-        Ok(())
-    }
-
-    fn module_name() -> &'static str {
-        "dropbear_input"
-    }
-}
+}
\ No newline at end of file
diff --git a/eucalyptus-core/src/lib.rs b/eucalyptus-core/src/lib.rs
index d0382f7..f8dab11 100644
--- a/eucalyptus-core/src/lib.rs
+++ b/eucalyptus-core/src/lib.rs
@@ -4,3 +4,4 @@ pub mod logging;
 pub mod scripting;
 pub mod states;
 pub mod utils;
+pub mod dropbear;
\ No newline at end of file
diff --git a/eucalyptus-core/src/scripting.rs b/eucalyptus-core/src/scripting.rs
index 18005c1..9f15955 100644
--- a/eucalyptus-core/src/scripting.rs
+++ b/eucalyptus-core/src/scripting.rs
@@ -1,33 +1,14 @@
-pub mod dropbear;
-pub mod build;
-
 use crate::input::InputState;
-use crate::scripting::dropbear::DropbearAPI;
 use crate::states::{EntityNode, PROJECT, SOURCE, ScriptComponent, Value};
+use boa_engine::property::PropertyKey;
+use boa_engine::{Context, JsString, JsValue, Source};
 use dropbear_engine::entity::{AdoptedEntity, Transform};
 use hecs::{Entity, World};
-use wasmer::{FunctionEnv, Imports, Instance, Module, Store, imports};
 use std::path::PathBuf;
+use std::str::FromStr;
 use std::sync::Arc;
 use std::{collections::HashMap, fs};
 
-/// A trait that describes a module that can be registered.
-pub trait ScriptableModule {
-    type Data;
-
-    fn register(data: &Self::Data, imports: &mut Imports, store: &mut Store) -> anyhow::Result<()>;
-
-    fn module_name() -> &'static str;
-}
-
-pub trait ScriptableModuleWithEnv {
-    type T;
-
-    fn register(env: &FunctionEnv<Self::T>, imports: &mut Imports, store: &mut Store) -> anyhow::Result<()>;
-
-    fn module_name() -> &'static str;
-}
-
 pub const TEMPLATE_SCRIPT: &'static str = include_str!("../../resources/template.ts");
 
 pub enum ScriptAction {
@@ -107,20 +88,14 @@ impl DropbearScriptingAPIContext {
 }
 
 pub struct ScriptManager {
-    pub store: Store,
-    compiled_scripts: HashMap<String, Module>,
-    entity_script_data: HashMap<hecs::Entity, u32>,
+    compiled_scripts: HashMap<String, String>,
     script_context: DropbearScriptingAPIContext,
 }
 
 impl ScriptManager {
-    pub fn new() -> anyhow::Result<Self> {
-        let store = Store::default();
-        
+    pub fn new() -> anyhow::Result<Self> {        
         let result = Self {
-            store,
             compiled_scripts: HashMap::new(),
-            entity_script_data: HashMap::new(),
             script_context: DropbearScriptingAPIContext::new(),
         };
 
@@ -128,9 +103,8 @@ impl ScriptManager {
         Ok(result)
     }
 
-    pub fn load_script(&mut self, script_name: &String, script_content: impl AsRef<[u8]>) -> anyhow::Result<String> {
-        let module = Module::new(self.store.engine(), script_content)?;
-        self.compiled_scripts.insert(script_name.clone(), module);
+    pub fn load_script(&mut self, script_name: &String, script_content: String) -> anyhow::Result<String> {
+        self.compiled_scripts.insert(script_name.clone(), script_content);
         log::debug!("Loaded script [{}]", script_name);
         Ok(script_name.clone())
     }
@@ -144,31 +118,24 @@ impl ScriptManager {
     ) -> anyhow::Result<()> {
         log_once::debug_once!("init_entity_script: {} for {:?}", script_name, entity_id);
 
-        if let Some(module) = self.compiled_scripts.get(script_name).cloned() {
+        if let Some(script_source) = self.compiled_scripts.get(script_name) {
             self.script_context.set_context(entity_id, world.clone(), input_state);
 
-            let import_obj = self.create_imports()?;
-            let instance = Instance::new(&mut self.store, &module, &import_obj)?;
+            let mut context = Context::default();
+            self.expose(&mut context);
 
-            if let Ok(alloc_func) = instance.exports.get_function("__alloc") {
-                let size = std::mem::size_of::<Transform>() as i32;
-                let result = alloc_func.call(&mut self.store, &[size.into()])?;
-                if let Some(wasmer::Value::I32(ptr)) = result.get(0) {
-                    self.entity_script_data.insert(entity_id, *ptr as u32);
-                }
-            }
+            context.eval(Source::from_bytes(script_source.clone().as_bytes())).map_err(|e| anyhow::anyhow!("{}", e))?;
 
-            self.sync_entity_to_memory(entity_id, world, &instance)?;
+            let load = context.global_object().get(PropertyKey::String(JsString::from_str("load")?), &mut context).map_err(|e| anyhow::anyhow!("{}", e))?;
 
-            if let Ok(init_func) = instance.exports.get_function("init") {
-                init_func.call(&mut self.store, &[])?;
+            if load.is_callable() {
+                let _ = load.as_callable().unwrap().call(&JsValue::undefined(), &[], &mut context);
+            } else {
+                log::warn!("Unable to call load in script {}: Load is not a callable function", script_name)
             }
 
-            self.sync_memory_to_entity(entity_id, world, &instance)?;
-
             self.script_context.clear_context();
-
-            Ok(())
+            return Ok(());
         } else {
             Err(anyhow::anyhow!("Script '{}' not found", script_name))
         }
@@ -186,80 +153,31 @@ impl ScriptManager {
 
         if let Some(module) = self.compiled_scripts.get(script_name).cloned() {
             self.script_context.set_context(entity_id, world.clone(), input_state);
-            
-            let import_object = self.create_imports()?;
-            let instance = Instance::new(&mut self.store, &module, &import_object)?;
-            
-            self.sync_entity_to_memory(entity_id, world, &instance)?;
-            
-            if let Ok(update_func) = instance.exports.get_function("update") {
-                let dt_value = wasmer::Value::F32(dt);
-                update_func.call(&mut self.store, &[dt_value])?;
-            }
-            
-            self.sync_memory_to_entity(entity_id, world, &instance)?;
-            
-            self.script_context.clear_context();
-            
-        } else {
-            log_once::error_once!("Unable to fetch compiled scripts for entity {:?}. Script Name: {}", entity_id, script_name);
-        }
-        Ok(())
-    }
 
-    pub fn remove_entity_script(&mut self, entity_id: hecs::Entity) {
-        self.entity_script_data.remove(&entity_id);
-    }
+            let mut context = Context::default();
+            self.expose(&mut context);
 
-    fn sync_entity_to_memory(&self, entity_id: hecs::Entity, world: &mut Arc<World>, instance: &Instance) -> anyhow::Result<()> {
-        if let Some(&memory_offset) = self.entity_script_data.get(&entity_id) {
-            let memory = instance.exports.get_memory("memory")?;
-            let memory_view = memory.view(&self.store);
-
-            if let Ok(transform) = Arc::get_mut(world).unwrap().query_one_mut::<&Transform>(entity_id) {
-                let transform_bytes = unsafe { std::slice::from_raw_parts(
-                    transform as *const Transform as *const u8, 
-                    std::mem::size_of::<Transform>()
-                )};
-                
-                for (i, &byte) in transform_bytes.iter().enumerate() {
-                    memory_view.write_u8((memory_offset + i as u32).into(), byte)?;
-                }
-            }
-        }
-        Ok(())
-    }
+            context.eval(Source::from_bytes(module.as_bytes())).map_err(|e| anyhow::anyhow!("{}", e))?;
 
-    fn sync_memory_to_entity(&self, entity_id: hecs::Entity, world: &mut Arc<World>, instance: &Instance) -> anyhow::Result<()> {
-        if let Some(&memory_offset) = self.entity_script_data.get(&entity_id) {
-            let memory = instance.exports.get_memory("memory")?;
-            let memory_view = memory.view(&self.store);
+            let update = context.global_object().get(PropertyKey::String(JsString::from_str("update")?), &mut context).map_err(|e| anyhow::anyhow!("{}", e))?;
 
-            Self::update::<Transform>(memory_offset, &memory_view, world, &entity_id)?;
-        }
-        Ok(())
-    }
+            if update.is_callable() {
+                let dt_val = JsValue::from(dt);
+                let _ = update.as_callable().unwrap().call(&JsValue::undefined(), &[dt_val], &mut context);
+            } else {
+                log::warn!("Unable to call update in script {}: Update is not a callable function", script_name)
+            }
 
-    fn update<T: Send + Sync + 'static>(memory_offset: u32, memory_view: &wasmer::MemoryView<'_>, world: &mut Arc<World>, entity_id: &hecs::Entity) -> anyhow::Result<()> {
-        let mut obj_bytes = vec![0u8; std::mem::size_of::<T>()];
-        for (i, byte) in obj_bytes.iter_mut().enumerate() {
-            *byte = memory_view.read_u8((memory_offset + i as u32).into())?;
+            self.script_context.clear_context();
+            return Ok(())
+        } else {
+            log_once::error_once!("Unable to fetch compiled scripts for entity {:?}. Script Name: {}", entity_id, script_name);
         }
-
-        let obj = unsafe {
-            std::ptr::read(obj_bytes.as_ptr() as *const T)
-        };
-
-        Arc::get_mut(world).unwrap().insert_one(*entity_id, obj)?;
         Ok(())
     }
 
-    fn create_imports(&mut self) -> anyhow::Result<Imports> {
-        let mut imports = imports! {};
-
-        DropbearAPI::register(&self.script_context, &mut imports, &mut self.store)?;
+    pub fn expose(&self, _context: &mut Context) {
 
-        Ok(imports)
     }
 }
 
diff --git a/eucalyptus-core/src/scripting/build.rs b/eucalyptus-core/src/scripting/build.rs
deleted file mode 100644
index faf1983..0000000
--- a/eucalyptus-core/src/scripting/build.rs
+++ /dev/null
@@ -1,540 +0,0 @@
-use std::path::PathBuf;
-use std::process::Command;
-use app_dirs2::{AppInfo, AppDataType, app_dir};
-use tokio::fs;
-use tokio::io::AsyncWriteExt;
-use tokio::sync::mpsc::UnboundedSender;
-use futures_util::StreamExt;
-
-const GLEAM_VERSION: &'static str = "1.12.0";
-const BUN_VERSION: &'static str = "1.2.22";
-const JAVY_VERSION: &'static str = "6.0.0";
-
-pub const APP_INFO: AppInfo = AppInfo {
-    name: "Eucalyptus",
-    author: "4tkbytes",
-};
-
-pub enum InstallStatus {
-    NotStarted,
-    InProgress {
-        tool: String,
-        step: String,
-        progress: f32,
-    },
-    Success,
-    Failed(String),
-}
-
-/// Compiles a gleam project into WASM through a pipeline. 
-pub struct GleamScriptCompiler {
-    #[allow(dead_code)]
-    project_location: PathBuf,
-}
-
-impl GleamScriptCompiler {
-    pub fn new(project_location: &PathBuf) -> Self {
-        GleamScriptCompiler {
-            project_location: project_location.clone(),
-        }
-    }
-
-    pub async fn build(self, sender: Option<UnboundedSender<InstallStatus>>) -> anyhow::Result<()> {
-        Self::ensure_dependencies(sender).await?;
-        Ok(())
-    }
-
-    pub async fn ensure_dependencies(sender: Option<UnboundedSender<InstallStatus>>) -> anyhow::Result<()> {
-        println!("Checking dependencies...");
-        
-        if let Some(ref s) = sender {
-            let _ = s.send(InstallStatus::InProgress {
-                tool: "None".to_string(),
-                step: "Checking existing tools...".to_string(),
-                progress: 0.05,
-            });
-        }
-
-        let gleam_available = Self::check_tool_in_path("gleam").await;
-        let bun_available = Self::check_tool_in_path("bun").await;
-        let javy_available = Self::check_tool_in_path("javy").await;
-
-        if gleam_available && bun_available && javy_available {
-            println!("All dependencies found in PATH");
-            if let Some(ref s) = sender {
-                let _ = s.send(InstallStatus::Success);
-            }
-            return Ok(());
-        }
-
-        if !(cfg!(target_os = "windows") || cfg!(target_os = "linux") || cfg!(target_os = "macos")) {
-            anyhow::bail!("The operating system is not supported for building the Gleam project")
-        }
-
-        let app_dir = app_dir(AppDataType::UserData, &APP_INFO, "")
-            .map_err(|e| anyhow::anyhow!("Failed to get app directory: {}", e))?;
-
-        let tools_to_install: Vec<(&str, bool)> = vec![
-            ("Gleam", gleam_available),
-            ("Bun", bun_available),
-            ("Javy", javy_available),
-        ];
-        let total_to_install = tools_to_install.iter().filter(|(_, avail)| !avail).count();
-        let mut installed_count = 0;
-
-        if !gleam_available {
-            if let Some(ref s) = sender.clone() {
-                let _ = s.send(InstallStatus::InProgress {
-                    tool: "Gleam".to_string(),
-                    step: "Downloading Gleam...".to_string(),
-                    progress: 0.2 + (installed_count as f32 / total_to_install as f32) * 0.6,
-                });
-            }
-            Self::download_gleam(&app_dir, sender.clone()).await?;
-            installed_count += 1;
-        } else {
-            if let Some(ref s) = sender.clone() {
-                let _ = s.send(InstallStatus::InProgress {
-                    tool: "Gleam".to_string(),
-                    step: "Done!".to_string(),
-                    progress: 1.0,
-                });
-            }
-            installed_count += 1;
-        }
-
-        if !bun_available {
-            if let Some(ref s) = sender.clone() {
-                let _ = s.send(InstallStatus::InProgress {
-                    tool: "Bun".to_string(),
-                    step: "Downloading Bun...".to_string(),
-                    progress: 0.2 + (installed_count as f32 / total_to_install as f32) * 0.6,
-                });
-            }
-            Self::download_bun(&app_dir, sender.clone()).await?;
-            installed_count += 1;
-        } else {
-            if let Some(ref s) = sender.clone() {
-                let _ = s.send(InstallStatus::InProgress {
-                    tool: "Bun".to_string(),
-                    step: "Done!".to_string(),
-                    progress: 1.0,
-                });
-            }
-            installed_count += 1;
-        }
-
-        if !javy_available {
-            if let Some(ref s) = sender.clone() {
-                let _ = s.send(InstallStatus::InProgress {
-                    tool: "Javy".to_string(),
-                    step: "Downloading Javy...".to_string(),
-                    progress: 0.2 + (installed_count as f32 / total_to_install as f32) * 0.6,
-                });
-            }
-            Self::download_javy(&app_dir, sender.clone()).await?;
-            installed_count += 1;
-        } else {
-            if let Some(ref s) = sender.clone() {
-                let _ = s.send(InstallStatus::InProgress {
-                    tool: "Javy".to_string(),
-                    step: "Done!".to_string(),
-                    progress: 1.0,
-                });
-            }
-            installed_count += 1;
-        }
-
-        if let Some(ref s) = sender.clone() {
-            let _ = s.send(InstallStatus::Success);
-        }
-
-        println!("All {} dependencies installed successfully", installed_count);
-        Ok(())
-    }
-
-    async fn check_tool_in_path(tool: &str) -> bool {
-        let cmd = if cfg!(target_os = "windows") {
-            Command::new("where").arg(tool).output()
-        } else {
-            Command::new("which").arg(tool).output()
-        };
-
-        match cmd {
-            Ok(output) => output.status.success(),
-            Err(_) => false,
-        }
-    }
-
-    pub async fn download_gleam(app_dir: &PathBuf, sender: Option<UnboundedSender<InstallStatus>>) -> anyhow::Result<()> {
-        let gleam_dir = app_dir.join("dependencies").join("gleam").join(GLEAM_VERSION);
-        
-        if gleam_dir.exists() {
-            println!("Gleam v{} already cached at {}", GLEAM_VERSION, app_dir.display());
-            return Ok(());
-        }
-
-        println!("Downloading Gleam v{}...", GLEAM_VERSION);
-        
-        let gleam_link = Self::get_gleam_download_url()?;
-        Self::download_and_extract(&gleam_link, &gleam_dir, "gleam", sender).await?;
-        
-        println!("Gleam v{} downloaded successfully", GLEAM_VERSION);
-        Ok(())
-    }
-
-    pub async fn download_bun(app_dir: &PathBuf, sender: Option<UnboundedSender<InstallStatus>>) -> anyhow::Result<()> {
-        let bun_dir = app_dir.join("dependencies").join("bun").join(BUN_VERSION);
-        
-        if bun_dir.exists() {
-            println!("Bun v{} already cached at {}", BUN_VERSION, app_dir.display());
-            return Ok(());
-        }
-
-        println!("Downloading Bun v{}...", BUN_VERSION);
-        
-        let bun_link = Self::get_bun_download_url()?;
-        Self::download_and_extract(&bun_link, &bun_dir, "bun", sender).await?;
-        
-        println!("Bun v{} downloaded successfully", BUN_VERSION);
-        Ok(())
-    }
-
-    pub async fn download_javy(app_dir: &PathBuf, sender: Option<UnboundedSender<InstallStatus>>) -> anyhow::Result<()> {
-        let javy_dir = app_dir.join("dependencies").join("javy").join(JAVY_VERSION);
-        
-        if javy_dir.exists() {
-            println!("Javy v{} already cached at {}", JAVY_VERSION, app_dir.display());
-            return Ok(());
-        }
-
-        println!("Downloading Javy v{}...", JAVY_VERSION);
-        
-        let javy_link = Self::get_javy_download_url()?;
-        Self::download_and_extract(&javy_link, &javy_dir, "javy", sender).await?;
-        
-        println!("Javy v{} downloaded successfully", JAVY_VERSION);
-        Ok(())
-    }
-
-    async fn download_and_extract(
-        url: &str, 
-        target_dir: &PathBuf, 
-        tool_name: &str, 
-        sender: Option<UnboundedSender<InstallStatus>>
-    ) -> anyhow::Result<()> {
-        if let Some(ref s) = sender {
-            let _ = s.send(InstallStatus::InProgress {
-                step: format!("Creating directories for {}...", tool_name),
-                progress: 0.0,
-                tool: tool_name.to_string(),
-            });
-        }
-
-        fs::create_dir_all(target_dir).await?;
-
-        if let Some(ref s) = sender {
-            let _ = s.send(InstallStatus::InProgress {
-                step: format!("Downloading {}...", tool_name),
-                progress: 0.3,
-                tool: tool_name.to_string(),
-            });
-        }
-
-        let response = reqwest::get(url).await?;
-        let total_size = response.content_length().unwrap_or(0);
-        let mut downloaded = 0;
-        let mut stream = response.bytes_stream();
-
-        let temp_file = target_dir.join(format!("{}_download", tool_name));
-        let mut file = fs::File::create(&temp_file).await?;
-
-        while let Some(item) = stream.next().await {
-            let bytes = item?;
-            file.write_all(&bytes).await?;
-            downloaded += bytes.len() as u64;
-
-            if let Some(ref s) = sender {
-                let progress = 0.3 + (downloaded as f32 / total_size as f32) * 0.4;
-                let _ = s.send(InstallStatus::InProgress {
-                    step: format!("Downloading {}...", tool_name),
-                    progress,
-                    tool: tool_name.to_string(),
-                });
-            }
-        }
-
-        file.sync_all().await?;
-        drop(file);
-
-        if let Some(ref s) = sender {
-            let _ = s.send(InstallStatus::InProgress {
-                step: format!("Extracting {}...", tool_name),
-                progress: 0.7,
-                tool: tool_name.to_string(),
-            });
-        }
-
-        if url.ends_with(".zip") {
-            Self::extract_zip(&temp_file, target_dir).await?;
-        } else if url.ends_with(".tar.gz") {
-            Self::extract_tar_gz(&temp_file, target_dir).await?;
-        } else if url.ends_with(".gz") {
-            Self::extract_gz(&temp_file, target_dir, tool_name).await?;
-        }
-
-        fs::remove_file(&temp_file).await?;
-
-        if let Some(ref s) = sender {
-            let _ = s.send(InstallStatus::InProgress {
-                step: format!("{} installation complete", tool_name),
-                progress: 0.9,
-                tool: tool_name.to_string(),
-            });
-        }
-
-        Ok(())
-    }
-
-    async fn extract_zip(archive: &PathBuf, target_dir: &PathBuf) -> anyhow::Result<()> {
-        let file = std::fs::File::open(archive)?;
-        let mut archive = zip::ZipArchive::new(file)?;
-        
-        for i in 0..archive.len() {
-            let mut file = archive.by_index(i)?;
-            let outpath = target_dir.join(file.name());
-            
-            if file.is_dir() {
-                fs::create_dir_all(&outpath).await?;
-            } else {
-                if let Some(p) = outpath.parent() {
-                    fs::create_dir_all(p).await?;
-                }
-                let mut outfile = fs::File::create(&outpath).await?;
-                let mut buffer = Vec::new();
-                std::io::Read::read_to_end(&mut file, &mut buffer)?;
-                outfile.write_all(&buffer).await?;
-            }
-        }
-        Ok(())
-    }
-
-    async fn extract_tar_gz(archive: &PathBuf, target_dir: &PathBuf) -> anyhow::Result<()> {
-        let file = std::fs::File::open(archive)?;
-        let tar = flate2::read::GzDecoder::new(file);
-        let mut archive = tar::Archive::new(tar);
-        
-        for entry in archive.entries()? {
-            let mut entry = entry?;
-            let path = target_dir.join(entry.path()?);
-            entry.unpack(path)?;
-        }
-        Ok(())
-    }
-
-    async fn extract_gz(archive: &PathBuf, target_dir: &PathBuf, tool_name: &str) -> anyhow::Result<()> {
-        let file = std::fs::File::open(archive)?;
-        let mut decoder = flate2::read::GzDecoder::new(file);
-        let mut buffer = Vec::new();
-        std::io::Read::read_to_end(&mut decoder, &mut buffer)?;
-        
-        let exe_name = if cfg!(target_os = "windows") {
-            format!("{}.exe", tool_name)
-        } else {
-            tool_name.to_string()
-        };
-        
-        let output_path = target_dir.join(exe_name);
-        let mut output_file = fs::File::create(&output_path).await?;
-        output_file.write_all(&buffer).await?;
-        
-        #[cfg(unix)]
-        {
-            use std::os::unix::fs::PermissionsExt;
-            let mut perms = output_file.metadata().await?.permissions();
-            perms.set_mode(0o755);
-            fs::set_permissions(&output_path, perms).await?;
-        }
-        
-        Ok(())
-    }
-
-    fn get_gleam_download_url() -> anyhow::Result<String> {
-        let gleam_link = {
-            #[cfg(target_os = "windows")]
-            {
-                let arch = {
-                    if cfg!(target_arch = "aarch64") {
-                        "aarch64"
-                    } else if cfg!(target_arch = "x86_64") {
-                        "x86_64"
-                    } else {
-                        anyhow::bail!("This architecture is not supported for building the gleam project");
-                    }
-                };
-                format!("https://github.com/gleam-lang/gleam/releases/download/v{}/gleam-v{}-{}-pc-windows-msvc.zip",
-                    GLEAM_VERSION,
-                    GLEAM_VERSION,
-                    arch,
-                )
-            }
-
-            #[cfg(target_os = "linux")]
-            {
-                let arch = {
-                    if cfg!(target_arch = "aarch64") {
-                        "aarch64"
-                    } else if cfg!(target_arch = "x86_64") {
-                        "x86_64"
-                    } else {
-                        anyhow::bail!("This architecture is not supported for building the gleam project");
-                    }
-                };
-                format!("https://github.com/gleam-lang/gleam/releases/download/v{}/gleam-v{}-{}-unknown-linux-musl.tar.gz",
-                    GLEAM_VERSION,
-                    GLEAM_VERSION,
-                    arch,
-                )
-            }
-
-            #[cfg(target_os = "macos")] 
-            {
-                let arch = {
-                    if cfg!(target_arch = "aarch64") {
-                        "aarch64"
-                    } else if cfg!(target_arch = "x86_64") {
-                        "x86_64"
-                    } else {
-                        anyhow::bail!("This architecture is not supported for building the gleam project");
-                    }
-                };
-                format!("https://github.com/gleam-lang/gleam/releases/download/v{}/gleam-v{}-{}-apple-darwin.tar.gz",
-                    GLEAM_VERSION,
-                    GLEAM_VERSION,
-                    arch,
-                )
-            }
-        };
-        Ok(gleam_link)
-    }
-
-    fn get_bun_download_url() -> anyhow::Result<String> {
-        let bun_link = {
-            #[cfg(target_os = "windows")]
-            {
-                let arch = {
-                    if cfg!(target_arch = "aarch64") {
-                        "aarch64"
-                    } else if cfg!(target_arch = "x86_64") {
-                        "x64"
-                    } else {
-                        anyhow::bail!("This architecture is not supported for building the gleam project");
-                    }
-                };
-                format!("https://github.com/oven-sh/bun/releases/download/bun-v{}/bun-windows-{}.zip",
-                    BUN_VERSION,
-                    arch,
-                )
-            }
-
-            #[cfg(target_os = "linux")]
-            {
-                let arch = {
-                    if cfg!(target_arch = "aarch64") {
-                        "aarch64"
-                    } else if cfg!(target_arch = "x86_64") {
-                        "x64"
-                    } else {
-                        anyhow::bail!("This architecture is not supported for building the gleam project");
-                    }
-                };
-                format!("https://github.com/oven-sh/bun/releases/download/bun-v{}/bun-linux-{}.zip",
-                    BUN_VERSION,
-                    arch,
-                )
-            }
-
-            #[cfg(target_os = "macos")] 
-            {
-                let arch = {
-                    if cfg!(target_arch = "aarch64") {
-                        "aarch64"
-                    } else if cfg!(target_arch = "x86_64") {
-                        "x64"
-                    } else {
-                        anyhow::bail!("This architecture is not supported for building the gleam project");
-                    }
-                };
-                format!("https://github.com/oven-sh/bun/releases/download/bun-v{}/bun-darwin-{}.zip",
-                    BUN_VERSION,
-                    arch,
-                )
-            }
-        };
-        Ok(bun_link)
-    }
-
-    fn get_javy_download_url() -> anyhow::Result<String> {
-        let javy_link = {
-            #[cfg(target_os = "windows")]
-            {
-                let arch = {
-                    if cfg!(target_arch = "aarch64") {
-                        anyhow::bail!("This arch is not available for prebuilt download. Please build this from source");
-                    } else if cfg!(target_arch = "x86_64") {
-                        "x86_64"
-                    } else {
-                        anyhow::bail!("This architecture is not supported for building the gleam project");
-                    }
-                };
-                format!("https://github.com/bytecodealliance/javy/releases/download/v{}/javy-{}-windows-v{}.gz",
-                    JAVY_VERSION,
-                    arch,
-                    JAVY_VERSION
-                )
-            }
-
-            #[cfg(target_os = "linux")]
-            {
-                let arch = {
-                    if cfg!(target_arch = "aarch64") {
-                        "arm"
-                    } else if cfg!(target_arch = "x86_64") {
-                        "x86_64"
-                    } else {
-                        anyhow::bail!("This architecture is not supported for building the gleam project");
-                    }
-                };
-                format!("https://github.com/bytecodealliance/javy/releases/download/v{}/javy-{}-linux-v{}.gz",
-                    JAVY_VERSION,
-                    arch,
-                    JAVY_VERSION
-                )
-            }
-
-            #[cfg(target_os = "macos")] 
-            {
-                let arch = {
-                    if cfg!(target_arch = "aarch64") {
-                        "arm"
-                    } else if cfg!(target_arch = "x86_64") {
-                        "x86_64"
-                    } else {
-                        anyhow::bail!("This architecture is not supported for building the gleam project");
-                    }
-                };
-                format!("https://github.com/bytecodealliance/javy/releases/download/v{}/javy-{}-macos-v{}.gz",
-                    JAVY_VERSION,
-                    arch,
-                    JAVY_VERSION
-                )
-            }
-        };
-        Ok(javy_link)
-    }
-}
-
-#[tokio::test]
-async fn check_if_dependencies_install() {
-    GleamScriptCompiler::ensure_dependencies(None).await.unwrap();
-}
\ No newline at end of file
diff --git a/eucalyptus-core/src/scripting/dropbear.rs b/eucalyptus-core/src/scripting/dropbear.rs
deleted file mode 100644
index c226442..0000000
--- a/eucalyptus-core/src/scripting/dropbear.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-
-use wasmer::FunctionEnv;
-
-use crate::{input::InputState, scripting::{DropbearScriptingAPIContext, ScriptableModule, ScriptableModuleWithEnv}};
-
-pub struct DropbearAPI;
-
-impl ScriptableModule for DropbearAPI {
-    type Data = DropbearScriptingAPIContext;
-
-    fn register(data: &Self::Data, imports: &mut wasmer::Imports, store: &mut wasmer::Store) -> anyhow::Result<()> {
-        let env = FunctionEnv::new(store, data.clone());
-
-        InputState::register(&env, imports, store)?;
-
-        Ok(())
-    }
-
-    fn module_name() -> &'static str {
-        "dropbear"
-    }
-}
\ No newline at end of file
diff --git a/eucalyptus-editor/Cargo.toml b/eucalyptus-editor/Cargo.toml
index f841b05..f70338c 100644
--- a/eucalyptus-editor/Cargo.toml
+++ b/eucalyptus-editor/Cargo.toml
@@ -36,6 +36,10 @@ walkdir.workspace = true
 zip.workspace = true
 tokio.workspace = true
 async-trait.workspace = true
+reqwest.workspace = true
+flate2.workspace = true
+tar.workspace = true
+futures-util.workspace = true
 
 [target.'cfg(not(target_os = "android"))'.dependencies]
 rfd.workspace = true
diff --git a/eucalyptus-editor/src/build/gleam.rs b/eucalyptus-editor/src/build/gleam.rs
new file mode 100644
index 0000000..565beb2
--- /dev/null
+++ b/eucalyptus-editor/src/build/gleam.rs
@@ -0,0 +1,544 @@
+use std::path::PathBuf;
+use std::process::Command;
+use app_dirs2::{AppInfo, AppDataType, app_dir};
+use tokio::fs;
+use tokio::io::AsyncWriteExt;
+use tokio::sync::mpsc::UnboundedSender;
+use futures_util::StreamExt;
+
+const GLEAM_VERSION: &'static str = "1.12.0";
+const BUN_VERSION: &'static str = "1.2.22";
+const JAVY_VERSION: &'static str = "6.0.0";
+
+pub const APP_INFO: AppInfo = AppInfo {
+    name: "Eucalyptus",
+    author: "4tkbytes",
+};
+
+pub enum InstallStatus {
+    NotStarted,
+    InProgress {
+        tool: String,
+        step: String,
+        progress: f32,
+    },
+    Success,
+    Failed(String),
+}
+
+/// Compiles a gleam project into WASM through a pipeline. 
+pub struct GleamScriptCompiler {
+    #[allow(dead_code)]
+    project_location: PathBuf,
+}
+
+impl GleamScriptCompiler {
+    pub fn new(project_location: &PathBuf) -> Self {
+        GleamScriptCompiler {
+            project_location: project_location.clone(),
+        }
+    }
+
+    pub async fn evaluate(&self) -> anyhow::Result<()> {
+        Ok(())
+    }
+
+    pub async fn build(&self, sender: Option<UnboundedSender<InstallStatus>>) -> anyhow::Result<()> {
+        Self::ensure_dependencies(sender).await?;
+        Ok(())
+    }
+
+    pub async fn ensure_dependencies(sender: Option<UnboundedSender<InstallStatus>>) -> anyhow::Result<()> {
+        println!("Checking dependencies...");
+        
+        if let Some(ref s) = sender {
+            let _ = s.send(InstallStatus::InProgress {
+                tool: "None".to_string(),
+                step: "Checking existing tools...".to_string(),
+                progress: 0.05,
+            });
+        }
+
+        let gleam_available = Self::check_tool_in_path("gleam").await;
+        let bun_available = Self::check_tool_in_path("bun").await;
+        let javy_available = Self::check_tool_in_path("javy").await;
+
+        if gleam_available && bun_available && javy_available {
+            println!("All dependencies found in PATH");
+            if let Some(ref s) = sender {
+                let _ = s.send(InstallStatus::Success);
+            }
+            return Ok(());
+        }
+
+        if !(cfg!(target_os = "windows") || cfg!(target_os = "linux") || cfg!(target_os = "macos")) {
+            anyhow::bail!("The operating system is not supported for building the Gleam project")
+        }
+
+        let app_dir = app_dir(AppDataType::UserData, &APP_INFO, "")
+            .map_err(|e| anyhow::anyhow!("Failed to get app directory: {}", e))?;
+
+        let tools_to_install: Vec<(&str, bool)> = vec![
+            ("Gleam", gleam_available),
+            ("Bun", bun_available),
+            ("Javy", javy_available),
+        ];
+        let total_to_install = tools_to_install.iter().filter(|(_, avail)| !avail).count();
+        let mut installed_count = 0;
+
+        if !gleam_available {
+            if let Some(ref s) = sender.clone() {
+                let _ = s.send(InstallStatus::InProgress {
+                    tool: "Gleam".to_string(),
+                    step: "Downloading Gleam...".to_string(),
+                    progress: 0.2 + (installed_count as f32 / total_to_install as f32) * 0.6,
+                });
+            }
+            Self::download_gleam(&app_dir, sender.clone()).await?;
+            installed_count += 1;
+        } else {
+            if let Some(ref s) = sender.clone() {
+                let _ = s.send(InstallStatus::InProgress {
+                    tool: "Gleam".to_string(),
+                    step: "Done!".to_string(),
+                    progress: 1.0,
+                });
+            }
+            installed_count += 1;
+        }
+
+        if !bun_available {
+            if let Some(ref s) = sender.clone() {
+                let _ = s.send(InstallStatus::InProgress {
+                    tool: "Bun".to_string(),
+                    step: "Downloading Bun...".to_string(),
+                    progress: 0.2 + (installed_count as f32 / total_to_install as f32) * 0.6,
+                });
+            }
+            Self::download_bun(&app_dir, sender.clone()).await?;
+            installed_count += 1;
+        } else {
+            if let Some(ref s) = sender.clone() {
+                let _ = s.send(InstallStatus::InProgress {
+                    tool: "Bun".to_string(),
+                    step: "Done!".to_string(),
+                    progress: 1.0,
+                });
+            }
+            installed_count += 1;
+        }
+
+        if !javy_available {
+            if let Some(ref s) = sender.clone() {
+                let _ = s.send(InstallStatus::InProgress {
+                    tool: "Javy".to_string(),
+                    step: "Downloading Javy...".to_string(),
+                    progress: 0.2 + (installed_count as f32 / total_to_install as f32) * 0.6,
+                });
+            }
+            Self::download_javy(&app_dir, sender.clone()).await?;
+            installed_count += 1;
+        } else {
+            if let Some(ref s) = sender.clone() {
+                let _ = s.send(InstallStatus::InProgress {
+                    tool: "Javy".to_string(),
+                    step: "Done!".to_string(),
+                    progress: 1.0,
+                });
+            }
+            installed_count += 1;
+        }
+
+        if let Some(ref s) = sender.clone() {
+            let _ = s.send(InstallStatus::Success);
+        }
+
+        println!("All {} dependencies installed successfully", installed_count);
+        Ok(())
+    }
+
+    async fn check_tool_in_path(tool: &str) -> bool {
+        let cmd = if cfg!(target_os = "windows") {
+            Command::new("where").arg(tool).output()
+        } else {
+            Command::new("which").arg(tool).output()
+        };
+
+        match cmd {
+            Ok(output) => output.status.success(),
+            Err(_) => false,
+        }
+    }
+
+    pub async fn download_gleam(app_dir: &PathBuf, sender: Option<UnboundedSender<InstallStatus>>) -> anyhow::Result<()> {
+        let gleam_dir = app_dir.join("dependencies").join("gleam").join(GLEAM_VERSION);
+        
+        if gleam_dir.exists() {
+            println!("Gleam v{} already cached at {}", GLEAM_VERSION, app_dir.display());
+            return Ok(());
+        }
+
+        println!("Downloading Gleam v{}...", GLEAM_VERSION);
+        
+        let gleam_link = Self::get_gleam_download_url()?;
+        Self::download_and_extract(&gleam_link, &gleam_dir, "gleam", sender).await?;
+        
+        println!("Gleam v{} downloaded successfully", GLEAM_VERSION);
+        Ok(())
+    }
+
+    pub async fn download_bun(app_dir: &PathBuf, sender: Option<UnboundedSender<InstallStatus>>) -> anyhow::Result<()> {
+        let bun_dir = app_dir.join("dependencies").join("bun").join(BUN_VERSION);
+        
+        if bun_dir.exists() {
+            println!("Bun v{} already cached at {}", BUN_VERSION, app_dir.display());
+            return Ok(());
+        }
+
+        println!("Downloading Bun v{}...", BUN_VERSION);
+        
+        let bun_link = Self::get_bun_download_url()?;
+        Self::download_and_extract(&bun_link, &bun_dir, "bun", sender).await?;
+        
+        println!("Bun v{} downloaded successfully", BUN_VERSION);
+        Ok(())
+    }
+
+    pub async fn download_javy(app_dir: &PathBuf, sender: Option<UnboundedSender<InstallStatus>>) -> anyhow::Result<()> {
+        let javy_dir = app_dir.join("dependencies").join("javy").join(JAVY_VERSION);
+        
+        if javy_dir.exists() {
+            println!("Javy v{} already cached at {}", JAVY_VERSION, app_dir.display());
+            return Ok(());
+        }
+
+        println!("Downloading Javy v{}...", JAVY_VERSION);
+        
+        let javy_link = Self::get_javy_download_url()?;
+        Self::download_and_extract(&javy_link, &javy_dir, "javy", sender).await?;
+        
+        println!("Javy v{} downloaded successfully", JAVY_VERSION);
+        Ok(())
+    }
+
+    async fn download_and_extract(
+        url: &str, 
+        target_dir: &PathBuf, 
+        tool_name: &str, 
+        sender: Option<UnboundedSender<InstallStatus>>
+    ) -> anyhow::Result<()> {
+        if let Some(ref s) = sender {
+            let _ = s.send(InstallStatus::InProgress {
+                step: format!("Creating directories for {}...", tool_name),
+                progress: 0.0,
+                tool: tool_name.to_string(),
+            });
+        }
+
+        fs::create_dir_all(target_dir).await?;
+
+        if let Some(ref s) = sender {
+            let _ = s.send(InstallStatus::InProgress {
+                step: format!("Downloading {}...", tool_name),
+                progress: 0.3,
+                tool: tool_name.to_string(),
+            });
+        }
+
+        let response = reqwest::get(url).await?;
+        let total_size = response.content_length().unwrap_or(0);
+        let mut downloaded = 0;
+        let mut stream = response.bytes_stream();
+
+        let temp_file = target_dir.join(format!("{}_download", tool_name));
+        let mut file = fs::File::create(&temp_file).await?;
+
+        while let Some(item) = stream.next().await {
+            let bytes = item?;
+            file.write_all(&bytes).await?;
+            downloaded += bytes.len() as u64;
+
+            if let Some(ref s) = sender {
+                let progress = 0.3 + (downloaded as f32 / total_size as f32) * 0.4;
+                let _ = s.send(InstallStatus::InProgress {
+                    step: format!("Downloading {}...", tool_name),
+                    progress,
+                    tool: tool_name.to_string(),
+                });
+            }
+        }
+
+        file.sync_all().await?;
+        drop(file);
+
+        if let Some(ref s) = sender {
+            let _ = s.send(InstallStatus::InProgress {
+                step: format!("Extracting {}...", tool_name),
+                progress: 0.7,
+                tool: tool_name.to_string(),
+            });
+        }
+
+        if url.ends_with(".zip") {
+            Self::extract_zip(&temp_file, target_dir).await?;
+        } else if url.ends_with(".tar.gz") {
+            Self::extract_tar_gz(&temp_file, target_dir).await?;
+        } else if url.ends_with(".gz") {
+            Self::extract_gz(&temp_file, target_dir, tool_name).await?;
+        }
+
+        fs::remove_file(&temp_file).await?;
+
+        if let Some(ref s) = sender {
+            let _ = s.send(InstallStatus::InProgress {
+                step: format!("{} installation complete", tool_name),
+                progress: 0.9,
+                tool: tool_name.to_string(),
+            });
+        }
+
+        Ok(())
+    }
+
+    async fn extract_zip(archive: &PathBuf, target_dir: &PathBuf) -> anyhow::Result<()> {
+        let file = std::fs::File::open(archive)?;
+        let mut archive = zip::ZipArchive::new(file)?;
+        
+        for i in 0..archive.len() {
+            let mut file = archive.by_index(i)?;
+            let outpath = target_dir.join(file.name());
+            
+            if file.is_dir() {
+                fs::create_dir_all(&outpath).await?;
+            } else {
+                if let Some(p) = outpath.parent() {
+                    fs::create_dir_all(p).await?;
+                }
+                let mut outfile = fs::File::create(&outpath).await?;
+                let mut buffer = Vec::new();
+                std::io::Read::read_to_end(&mut file, &mut buffer)?;
+                outfile.write_all(&buffer).await?;
+            }
+        }
+        Ok(())
+    }
+
+    async fn extract_tar_gz(archive: &PathBuf, target_dir: &PathBuf) -> anyhow::Result<()> {
+        let file = std::fs::File::open(archive)?;
+        let tar = flate2::read::GzDecoder::new(file);
+        let mut archive = tar::Archive::new(tar);
+        
+        for entry in archive.entries()? {
+            let mut entry = entry?;
+            let path = target_dir.join(entry.path()?);
+            entry.unpack(path)?;
+        }
+        Ok(())
+    }
+
+    async fn extract_gz(archive: &PathBuf, target_dir: &PathBuf, tool_name: &str) -> anyhow::Result<()> {
+        let file = std::fs::File::open(archive)?;
+        let mut decoder = flate2::read::GzDecoder::new(file);
+        let mut buffer = Vec::new();
+        std::io::Read::read_to_end(&mut decoder, &mut buffer)?;
+        
+        let exe_name = if cfg!(target_os = "windows") {
+            format!("{}.exe", tool_name)
+        } else {
+            tool_name.to_string()
+        };
+        
+        let output_path = target_dir.join(exe_name);
+        let mut output_file = fs::File::create(&output_path).await?;
+        output_file.write_all(&buffer).await?;
+        
+        #[cfg(unix)]
+        {
+            use std::os::unix::fs::PermissionsExt;
+            let mut perms = output_file.metadata().await?.permissions();
+            perms.set_mode(0o755);
+            fs::set_permissions(&output_path, perms).await?;
+        }
+        
+        Ok(())
+    }
+
+    fn get_gleam_download_url() -> anyhow::Result<String> {
+        let gleam_link = {
+            #[cfg(target_os = "windows")]
+            {
+                let arch = {
+                    if cfg!(target_arch = "aarch64") {
+                        "aarch64"
+                    } else if cfg!(target_arch = "x86_64") {
+                        "x86_64"
+                    } else {
+                        anyhow::bail!("This architecture is not supported for building the gleam project");
+                    }
+                };
+                format!("https://github.com/gleam-lang/gleam/releases/download/v{}/gleam-v{}-{}-pc-windows-msvc.zip",
+                    GLEAM_VERSION,
+                    GLEAM_VERSION,
+                    arch,
+                )
+            }
+
+            #[cfg(target_os = "linux")]
+            {
+                let arch = {
+                    if cfg!(target_arch = "aarch64") {
+                        "aarch64"
+                    } else if cfg!(target_arch = "x86_64") {
+                        "x86_64"
+                    } else {
+                        anyhow::bail!("This architecture is not supported for building the gleam project");
+                    }
+                };
+                format!("https://github.com/gleam-lang/gleam/releases/download/v{}/gleam-v{}-{}-unknown-linux-musl.tar.gz",
+                    GLEAM_VERSION,
+                    GLEAM_VERSION,
+                    arch,
+                )
+            }
+
+            #[cfg(target_os = "macos")] 
+            {
+                let arch = {
+                    if cfg!(target_arch = "aarch64") {
+                        "aarch64"
+                    } else if cfg!(target_arch = "x86_64") {
+                        "x86_64"
+                    } else {
+                        anyhow::bail!("This architecture is not supported for building the gleam project");
+                    }
+                };
+                format!("https://github.com/gleam-lang/gleam/releases/download/v{}/gleam-v{}-{}-apple-darwin.tar.gz",
+                    GLEAM_VERSION,
+                    GLEAM_VERSION,
+                    arch,
+                )
+            }
+        };
+        Ok(gleam_link)
+    }
+
+    fn get_bun_download_url() -> anyhow::Result<String> {
+        let bun_link = {
+            #[cfg(target_os = "windows")]
+            {
+                let arch = {
+                    if cfg!(target_arch = "aarch64") {
+                        "aarch64"
+                    } else if cfg!(target_arch = "x86_64") {
+                        "x64"
+                    } else {
+                        anyhow::bail!("This architecture is not supported for building the gleam project");
+                    }
+                };
+                format!("https://github.com/oven-sh/bun/releases/download/bun-v{}/bun-windows-{}.zip",
+                    BUN_VERSION,
+                    arch,
+                )
+            }
+
+            #[cfg(target_os = "linux")]
+            {
+                let arch = {
+                    if cfg!(target_arch = "aarch64") {
+                        "aarch64"
+                    } else if cfg!(target_arch = "x86_64") {
+                        "x64"
+                    } else {
+                        anyhow::bail!("This architecture is not supported for building the gleam project");
+                    }
+                };
+                format!("https://github.com/oven-sh/bun/releases/download/bun-v{}/bun-linux-{}.zip",
+                    BUN_VERSION,
+                    arch,
+                )
+            }
+
+            #[cfg(target_os = "macos")] 
+            {
+                let arch = {
+                    if cfg!(target_arch = "aarch64") {
+                        "aarch64"
+                    } else if cfg!(target_arch = "x86_64") {
+                        "x64"
+                    } else {
+                        anyhow::bail!("This architecture is not supported for building the gleam project");
+                    }
+                };
+                format!("https://github.com/oven-sh/bun/releases/download/bun-v{}/bun-darwin-{}.zip",
+                    BUN_VERSION,
+                    arch,
+                )
+            }
+        };
+        Ok(bun_link)
+    }
+
+    fn get_javy_download_url() -> anyhow::Result<String> {
+        let javy_link = {
+            #[cfg(target_os = "windows")]
+            {
+                let arch = {
+                    if cfg!(target_arch = "aarch64") {
+                        anyhow::bail!("This arch is not available for prebuilt download. Please build this from source");
+                    } else if cfg!(target_arch = "x86_64") {
+                        "x86_64"
+                    } else {
+                        anyhow::bail!("This architecture is not supported for building the gleam project");
+                    }
+                };
+                format!("https://github.com/bytecodealliance/javy/releases/download/v{}/javy-{}-windows-v{}.gz",
+                    JAVY_VERSION,
+                    arch,
+                    JAVY_VERSION
+                )
+            }
+
+            #[cfg(target_os = "linux")]
+            {
+                let arch = {
+                    if cfg!(target_arch = "aarch64") {
+                        "arm"
+                    } else if cfg!(target_arch = "x86_64") {
+                        "x86_64"
+                    } else {
+                        anyhow::bail!("This architecture is not supported for building the gleam project");
+                    }
+                };
+                format!("https://github.com/bytecodealliance/javy/releases/download/v{}/javy-{}-linux-v{}.gz",
+                    JAVY_VERSION,
+                    arch,
+                    JAVY_VERSION
+                )
+            }
+
+            #[cfg(target_os = "macos")] 
+            {
+                let arch = {
+                    if cfg!(target_arch = "aarch64") {
+                        "arm"
+                    } else if cfg!(target_arch = "x86_64") {
+                        "x86_64"
+                    } else {
+                        anyhow::bail!("This architecture is not supported for building the gleam project");
+                    }
+                };
+                format!("https://github.com/bytecodealliance/javy/releases/download/v{}/javy-{}-macos-v{}.gz",
+                    JAVY_VERSION,
+                    arch,
+                    JAVY_VERSION
+                )
+            }
+        };
+        Ok(javy_link)
+    }
+}
+
+#[tokio::test]
+async fn check_if_dependencies_install() {
+    GleamScriptCompiler::ensure_dependencies(None).await.unwrap();
+}
\ No newline at end of file
diff --git a/eucalyptus-editor/src/build/mod.rs b/eucalyptus-editor/src/build/mod.rs
index dfd18ae..ff61777 100644
--- a/eucalyptus-editor/src/build/mod.rs
+++ b/eucalyptus-editor/src/build/mod.rs
@@ -1,3 +1,5 @@
+pub mod gleam;
+
 use std::{collections::HashMap, fs, path::PathBuf, process::Command};
 
 use clap::ArgMatches;
diff --git a/eucalyptus-editor/src/debug.rs b/eucalyptus-editor/src/debug.rs
index 8249058..5fd55bb 100644
--- a/eucalyptus-editor/src/debug.rs
+++ b/eucalyptus-editor/src/debug.rs
@@ -1,9 +1,10 @@
 //! Used to aid with debugging any issues with the editor.
+use crate::build::gleam::GleamScriptCompiler;
+use crate::build::gleam::InstallStatus;
 use crate::editor::Signal;
 use egui::Ui;
 use egui::ProgressBar;
 use egui::Window;
-use eucalyptus_core::scripting::build::{GleamScriptCompiler, InstallStatus};
 use tokio::sync::mpsc;
 
 pub struct DependencyInstaller {
diff --git a/eucalyptus-editor/src/editor/scene.rs b/eucalyptus-editor/src/editor/scene.rs
index 6ba8d3e..803d4ab 100644
--- a/eucalyptus-editor/src/editor/scene.rs
+++ b/eucalyptus-editor/src/editor/scene.rs
@@ -547,7 +547,7 @@ impl Scene for Editor {
                             script.path.display()
                         );
 
-                        let bytes = match tokio::fs::read(&script.path).await {
+                        let bytes = match tokio::fs::read_to_string(&script.path).await {
                             Ok(val) => val,
                             Err(e) => {
                                 fatal!("Unable to read script {} to bytes because {}", &script.path.display(), e);
@@ -601,9 +601,10 @@ impl Scene for Editor {
 
                 self.switch_to_debug_camera();
 
-                for (entity_id, _) in Arc::get_mut(&mut self.world).unwrap().query::<&ScriptComponent>().iter() {
-                    self.script_manager.remove_entity_script(entity_id);
-                }
+                // already kills itself
+                // for (entity_id, _) in Arc::get_mut(&mut self.world).unwrap().query::<&ScriptComponent>().iter() {
+                //     self.script_manager.remove_entity_script(entity_id);
+                // }
 
                 success!("Exited play mode");
                 log::info!("Back to the editor you go...");
diff --git a/src/dropbear.gleam b/src/dropbear.gleam
index e69de29..555e244 100644
--- a/src/dropbear.gleam
+++ b/src/dropbear.gleam
@@ -0,0 +1,3 @@
+/// Queries the attached entity. Returns a serialized string to be decoded. 
+@external(javascript, "dropbear", "queryAttachedEntity")
+fn raw_query_attached_entity() -> String
\ No newline at end of file
diff --git a/src/input.gleam b/src/input.gleam
index d6e411f..e69de29 100644
--- a/src/input.gleam
+++ b/src/input.gleam
@@ -1,2 +0,0 @@
-@external(javascript, "dropbear_input", "is_key_pressed")
-fn is_key_pressed(key_code: Int) -> Int
\ No newline at end of file
diff --git a/src/memory.gleam b/src/memory.gleam
deleted file mode 100644
index 2f65c7b..0000000
--- a/src/memory.gleam
+++ /dev/null
@@ -1 +0,0 @@
-//// Internal library for WASM memory sharing between the dropbear game engine. 
\ No newline at end of file
diff --git a/src/memory.js b/src/memory.js
deleted file mode 100644
index 9c81ea6..0000000
--- a/src/memory.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/// Javascript library for managing memory in WebAssembly for the dropbear engine Gleam interface. 
-
-class WasmMemoryManager {
-    constructor(memory) {
-        this.memory = memory;
-        this.nextFreeOffset = 1024;
-        this.allocations = new Map();
-    }
-
-    /// Fetches the new view of the memory after the memory is refreshed
-    getView() {
-        return new DataView(this.memory.buffer);
-    }
-}
\ No newline at end of file