kitgit

tirbofish/dropbear · commit

620110dda0a0efebe3264e5e4a31f831d53530e3

wip: added JNI "*Native" java files and matched the jvmMain stuff. todo: implement the rust side, and get `cbindgen` working.

Unverified

Thribhu K <4tkbytes@pm.me> · 2025-12-30 05:51

view full diff

diff --git a/build.gradle.kts b/build.gradle.kts
index 91cb7c9..a076e42 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -2,7 +2,7 @@ plugins {
     alias(libs.plugins.kotlinMultiplatform)
     alias(libs.plugins.kotlinxSerialization)
     `maven-publish`
-    id("org.jetbrains.dokka") version "2.0.0"
+    id("org.jetbrains.dokka") version "2.1.0"
 }
 
 group = "com.dropbear"
@@ -36,9 +36,7 @@ val libPathProvider = provider {
 }
 
 kotlin {
-    jvm {
-
-    }
+    jvm { }
 
     val nativeTarget = when {
         isMacOs && isArm64 -> macosArm64("nativeLib")
@@ -100,7 +98,7 @@ kotlin {
     sourceSets {
         commonMain {
             dependencies {
-                api("org.jetbrains.kotlinx:kotlinx-datetime:0.6.0")
+                api("org.jetbrains.kotlinx:kotlinx-datetime:0.7.1")
             }
         }
         nativeMain {
@@ -129,7 +127,7 @@ kotlin {
     }
 }
 
-val extractJavaSources by tasks.registering(Copy::class) {
+val extractJavaSources by tasks.registering(Sync::class) {
     group = "jni"
     description = "Copies .java files from jvmMain/kotlin to a temp directory for header generation"
 
@@ -156,12 +154,19 @@ val generateJniHeaders by tasks.registering(JavaCompile::class) {
     val headerOutputDir = layout.buildDirectory.dir("generated/jni-headers")
     options.headerOutputDirectory.set(headerOutputDir)
 
+    doFirst {
+        val outDir = headerOutputDir.get().asFile
+        if (outDir.exists()) {
+            outDir.deleteRecursively()
+            outDir.mkdirs()
+        }
+    }
+
     doLast {
         println("Generated JNI Headers at: ${headerOutputDir.get().asFile.absolutePath}")
     }
 }
 
-
 tasks.named("jvmMainClasses") {
     dependsOn(generateJniHeaders)
 }
@@ -182,8 +187,12 @@ publishing {
 
             licenses {
                 license {
-                    name.set("dropbear engine License, Version 1.2")
-                    url.set("https://raw.githubusercontent.com/tirbofish/dropbear/refs/heads/main/LICENSE.md")
+                    name.set("MIT")
+                    url.set("https://opensource.org/license/mit")
+                }
+                license {
+                    name.set("Apache-2.0")
+                    url.set("https://www.apache.org/licenses/LICENSE-2.0")
                 }
             }
 
diff --git a/eucalyptus-editor/src/runtime/mod.rs b/eucalyptus-editor/src/runtime/mod.rs
index bf71fb2..a746092 100644
--- a/eucalyptus-editor/src/runtime/mod.rs
+++ b/eucalyptus-editor/src/runtime/mod.rs
@@ -381,6 +381,7 @@ impl PlayMode {
             if let Some(physics_state) = self.pending_physics_state.take() {
                 self.physics_state = physics_state;
             }
+            self.has_initial_resize_done = false;
             if let Some(new_camera) = self.pending_camera.take() {
                 self.active_camera = Some(new_camera);
             }
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 50632e7..8d0a1ea 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -6,6 +6,7 @@ pluginManagement {
         gradlePluginPortal()
     }
 }
+
 plugins {
     id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
 }
diff --git a/src/commonMain/kotlin/com/dropbear/Camera.kt b/src/commonMain/kotlin/com/dropbear/Camera.kt
deleted file mode 100644
index 3016200..0000000
--- a/src/commonMain/kotlin/com/dropbear/Camera.kt
+++ /dev/null
@@ -1,90 +0,0 @@
-package com.dropbear
-
-import com.dropbear.ecs.Component
-import com.dropbear.ecs.ComponentType
-import com.dropbear.math.Vector3D
-
-/**
- * Describes a 3D camera, as defined in `dropbear_engine::camera::Camera`
- */
-class Camera(
-    internal val entity: EntityId,
-): Component(entity, "Camera3D") {
-    var eye: Vector3D
-        get() = getCameraEye(entity)
-        set(value) = setCameraEye(entity, value)
-    var target: Vector3D
-        get() = getCameraTarget(entity)
-        set(value) = setCameraTarget(entity, value)
-    var up: Vector3D
-        get() = getCameraUp(entity)
-        set(value) = setCameraUp(entity, value)
-    val aspect: Double
-        get() = getCameraAspect(entity)
-    var fov_y: Double
-        get() = getCameraFovY(entity)
-        set(value) = setCameraFovY(entity, value)
-    var znear: Double
-        get() = getCameraZNear(entity)
-        set(value) = setCameraZNear(entity, value)
-    var zfar: Double
-        get() = getCameraZFar(entity)
-        set(value) = setCameraZFar(entity, value)
-    var yaw: Double
-        get() = getCameraYaw(entity)
-        set(value) = setCameraYaw(entity, value)
-    var pitch: Double
-        get() = getCameraPitch(entity)
-        set(value) = setCameraPitch(entity, value)
-    var speed: Double
-        get() = getCameraSpeed(entity)
-        set(value) = setCameraSpeed(entity, value)
-    var sensitivity: Double
-        get() = getCameraSensitivity(entity)
-        set(value) = setCameraSensitivity(entity, value)
-
-    override fun toString(): String {
-        return "Camera component of entity $entity \n" +
-                "eye: $eye\n" +
-                "target: $target\n" +
-                "up: $up\n " +
-                "aspect: $aspect \n" +
-                "fov_y: $fov_y \n" +
-                "znear: $znear \n" +
-                "zfar: $zfar \n" +
-                "yaw: $yaw \n" +
-                "pitch: $pitch" +
-                "speed: $speed" +
-                "sensitivity: $sensitivity"
-    }
-
-    companion object : ComponentType<Camera> {
-        override fun get(entityId: EntityId): Camera? {
-            return if (cameraExistsForEntity(entityId)) Camera(entityId) else null
-        }
-    }
-}
-
-expect fun Camera.getCameraEye(entity: EntityId): Vector3D
-expect fun Camera.setCameraEye(entity: EntityId, value: Vector3D)
-expect fun Camera.getCameraTarget(entity: EntityId): Vector3D
-expect fun Camera.setCameraTarget(entity: EntityId, value: Vector3D)
-expect fun Camera.getCameraUp(entity: EntityId): Vector3D
-expect fun Camera.setCameraUp(entity: EntityId, value: Vector3D)
-expect fun Camera.getCameraAspect(entity: EntityId): Double
-expect fun Camera.getCameraFovY(entity: EntityId): Double
-expect fun Camera.setCameraFovY(entity: EntityId, value: Double)
-expect fun Camera.getCameraZNear(entity: EntityId): Double
-expect fun Camera.setCameraZNear(entity: EntityId, value: Double)
-expect fun Camera.getCameraZFar(entity: EntityId): Double
-expect fun Camera.setCameraZFar(entity: EntityId, value: Double)
-expect fun Camera.getCameraYaw(entity: EntityId): Double
-expect fun Camera.setCameraYaw(entity: EntityId, value: Double)
-expect fun Camera.getCameraPitch(entity: EntityId): Double
-expect fun Camera.setCameraPitch(entity: EntityId, value: Double)
-expect fun Camera.getCameraSpeed(entity: EntityId): Double
-expect fun Camera.setCameraSpeed(entity: EntityId, value: Double)
-expect fun Camera.getCameraSensitivity(entity: EntityId): Double
-expect fun Camera.setCameraSensitivity(entity: EntityId, value: Double)
-
-expect fun cameraExistsForEntity(entity: EntityId): Boolean
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/CustomProperties.kt b/src/commonMain/kotlin/com/dropbear/CustomProperties.kt
deleted file mode 100644
index 49f3003..0000000
--- a/src/commonMain/kotlin/com/dropbear/CustomProperties.kt
+++ /dev/null
@@ -1,93 +0,0 @@
-package com.dropbear
-
-import com.dropbear.ecs.Component
-import com.dropbear.ecs.ComponentType
-import com.dropbear.math.Vector3
-
-class CustomProperties(val id: EntityId): Component(id, "CustomProperties") {
-    /**
-     * Fetches the property of the ModelProperty component on the entity.
-     */
-    inline fun <reified T> getProperty(key: String): T? {
-        return when (T::class) {
-            String::class -> getStringProperty(id.id, key) as T?
-            Long::class -> getLongProperty(id.id, key) as T?
-            Int::class -> getIntProperty(id.id, key) as T?
-            Double::class -> getDoubleProperty(id.id, key) as T?
-
-            Float::class -> getFloatProperty(id.id, key) as T?
-            Boolean::class -> getBoolProperty(id.id, key) as T?
-            FloatArray::class -> getVec3Property(id.id, key) as T?
-            else -> throw IllegalArgumentException("Unsupported property type: ${T::class}")
-        }
-    }
-
-    /**
-     * Sets a property of the ModelProperty component on the entity.
-     *
-     * # Supported types
-     * - [kotlin.String]
-     * - [kotlin.Long]
-     * - [kotlin.Int]
-     * - [kotlin.Double]
-     * - [kotlin.Float]
-     * - [kotlin.Boolean]
-     * - [com.dropbear.math.Vector3]
-     */
-    /**
-     * Sets a property of the ModelProperty component on the entity.
-     *
-     * # Supported types
-     * - [kotlin.String]
-     * - [kotlin.Long]
-     * - [kotlin.Int]
-     * - [kotlin.Double]
-     * - [kotlin.Float]
-     * - [kotlin.Boolean]
-     * - [com.dropbear.math.Vector3]
-     */
-    fun setProperty(key: String, value: Any) {
-        when (value) {
-            is String -> setStringProperty(id.id, key, value)
-            is Long -> setLongProperty(id.id, key, value)
-            is Int -> setIntProperty(id.id, key, value)
-            is Double -> setFloatProperty(id.id, key, value)
-            is Float -> setFloatProperty(id.id, key, value.toDouble())
-            is Boolean -> setBoolProperty(id.id, key, value)
-            is Vector3<*> -> {
-                val vec = value.asDoubleVector()
-                setVec3Property(id.id, key, floatArrayOf(vec.x.toFloat(), vec.y.toFloat(),
-                    vec.z.toFloat()
-                ))
-            }
-            is FloatArray -> {
-                require(value.size == 3) { "Vec3 property must have exactly 3 elements" }
-                setVec3Property(id.id, key, value)
-            }
-            else -> throw IllegalArgumentException("Unsupported property type: ${value::class}")
-        }
-    }
-
-    companion object : ComponentType<CustomProperties> {
-        override fun get(entityId: EntityId): CustomProperties? {
-            return if (customPropertiesExistsForEntity(entityId)) CustomProperties(entityId) else null
-        }
-    }
-}
-
-expect fun CustomProperties.getStringProperty(entityHandle: Long, label: String): String?
-expect fun CustomProperties.getIntProperty(entityHandle: Long, label: String): Int?
-expect fun CustomProperties.getLongProperty(entityHandle: Long, label: String): Long?
-expect fun CustomProperties.getDoubleProperty(entityHandle: Long, label: String): Double?
-expect fun CustomProperties.getFloatProperty(entityHandle: Long, label: String): Float?
-expect fun CustomProperties.getBoolProperty(entityHandle: Long, label: String): Boolean?
-expect fun CustomProperties.getVec3Property(entityHandle: Long, label: String): FloatArray?
-
-expect fun CustomProperties.setStringProperty(entityHandle: Long, label: String, value: String)
-expect fun CustomProperties.setIntProperty(entityHandle: Long, label: String, value: Int)
-expect fun CustomProperties.setLongProperty(entityHandle: Long, label: String, value: Long)
-expect fun CustomProperties.setFloatProperty(entityHandle: Long, label: String, value: Double)
-expect fun CustomProperties.setBoolProperty(entityHandle: Long, label: String, value: Boolean)
-expect fun CustomProperties.setVec3Property(entityHandle: Long, label: String, value: FloatArray)
-
-expect fun customPropertiesExistsForEntity(entityId: EntityId): Boolean
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/DropbearEngine.kt b/src/commonMain/kotlin/com/dropbear/DropbearEngine.kt
index 4666259..30c8dce 100644
--- a/src/commonMain/kotlin/com/dropbear/DropbearEngine.kt
+++ b/src/commonMain/kotlin/com/dropbear/DropbearEngine.kt
@@ -1,6 +1,7 @@
 package com.dropbear
 
 import com.dropbear.asset.AssetHandle
+import com.dropbear.components.Camera
 import com.dropbear.ffi.NativeEngine
 import com.dropbear.input.InputState
 import com.dropbear.logging.Logger
@@ -97,6 +98,5 @@ class DropbearEngine(val native: NativeEngine) {
 }
 
 expect fun getEntity(label: String): Long?
-expect fun getCamera(label: String): Camera?
 expect fun getAsset(eucaURI: String): Long?
 expect fun quit()
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/EntityId.kt b/src/commonMain/kotlin/com/dropbear/EntityId.kt
index b3c4d72..9d00d24 100644
--- a/src/commonMain/kotlin/com/dropbear/EntityId.kt
+++ b/src/commonMain/kotlin/com/dropbear/EntityId.kt
@@ -3,4 +3,4 @@ package com.dropbear
 /**
  * The ID of an entity (represented as a [Long])
  */
-data class EntityId(val id: Long)
\ No newline at end of file
+data class EntityId(val raw: Long)
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/EntityTransform.kt b/src/commonMain/kotlin/com/dropbear/EntityTransform.kt
deleted file mode 100644
index 42768d4..0000000
--- a/src/commonMain/kotlin/com/dropbear/EntityTransform.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.dropbear
-
-import com.dropbear.ecs.Component
-import com.dropbear.ecs.ComponentType
-import com.dropbear.math.Transform
-
-/**
- * A component that contains the local and world [Transform] of an entity.
- */
-class EntityTransform(val id: EntityId): Component(id, "EntityTransform") {
-    var local: Transform
-        get() = getLocalTransform(id)
-        set(value) = setLocalTransform(id, value)
-    var world: Transform
-        get() = getWorldTransform(id)
-        set(value) = setWorldTransform(id, value)
-
-    override fun toString(): String {
-        return "EntityTransform(id: $id, local=$local, world=$world)"
-    }
-
-    /**
-     * Walks up the world hierarchy to find the transform of the parent, then multiply/add
-     * to create a propagated [Transform].
-     */
-    fun propagate(): Transform {
-        return propagateTransform(id)
-    }
-
-    /**
-     * Merges the local and world transforms and return the merged [Transform]
-     */
-    fun sync(): Transform {
-        val scaledPos = local.position * world.scale
-        val rotatedPos = world.rotation * scaledPos
-        val finalPos = world.position + rotatedPos
-        val finalRot = world.rotation * local.rotation
-        val finalScale = world.scale * local.scale
-        return Transform(finalPos, finalRot, finalScale)
-    }
-
-    companion object : ComponentType<EntityTransform> {
-        override fun get(entityId: EntityId): EntityTransform? {
-            return if (entityTransformExistsForEntity(entityId)) {
-                EntityTransform(entityId)
-            } else {
-                null
-            }
-        }
-    }
-}
-
-expect fun EntityTransform.getLocalTransform(entityId: EntityId): Transform
-expect fun EntityTransform.setLocalTransform(entityId: EntityId, transform: Transform)
-expect fun EntityTransform.getWorldTransform(entityId: EntityId): Transform
-expect fun EntityTransform.setWorldTransform(entityId: EntityId, transform: Transform)
-expect fun EntityTransform.propagateTransform(entityId: EntityId): Transform
-
-expect fun entityTransformExistsForEntity(entityId: EntityId): Boolean
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/MeshRenderer.kt b/src/commonMain/kotlin/com/dropbear/MeshRenderer.kt
deleted file mode 100644
index c16c9d3..0000000
--- a/src/commonMain/kotlin/com/dropbear/MeshRenderer.kt
+++ /dev/null
@@ -1,72 +0,0 @@
-package com.dropbear
-
-import com.dropbear.asset.ModelHandle
-import com.dropbear.asset.TextureHandle
-import com.dropbear.ecs.Component
-import com.dropbear.ecs.ComponentType
-
-class MeshRenderer(val id: EntityId) : Component(id, "MeshRenderer") {
-
-    /**
-     * The active model currently assigned to this entity.
-     * Setting this to null removes the model.
-     *
-     * Usage:
-     * ```
-     * val handle = renderer.model
-     * renderer.model = newHandle
-     * ```
-     */
-    var model: ModelHandle?
-        get() {
-            return getModel(id)
-        }
-        set(value) {
-            setModel(id, value)
-        }
-
-    /**
-     * A list of all active Texture handles currently applied to the model.
-     */
-    val textures: List<TextureHandle>?
-        get() = getAllTextureIds(id)
-
-    /**
-     * Returns a list of material names available on the current model.
-     * Useful for knowing what keys to use in [getTexture] or [setTextureOverride].
-     */
-    val materialNames: List<String>
-        get() = getMaterialNames(id)
-
-    /**
-     * Fetches the texture assigned to a specific material slot.
-     * Returns null if the material doesn't exist or has no texture.
-     */
-    fun getTexture(materialName: String): TextureHandle? {
-        val rawId = getTexture(id, materialName)
-        return if (rawId == 0L) null else TextureHandle(rawId)
-    }
-
-    /**
-     * Overrides the texture for a specific material on the active model.
-     */
-    fun setTextureOverride(materialName: String, textureHandle: TextureHandle) {
-        setTextureOverride(id, materialName, textureHandle.raw())
-    }
-
-    companion object : ComponentType<MeshRenderer> {
-        override fun get(entityId: EntityId): MeshRenderer? {
-            return if (meshRendererExistsForEntity(entityId)) MeshRenderer(entityId) else null
-        }
-    }
-}
-
-expect fun MeshRenderer.getModel(id: EntityId): ModelHandle?
-expect fun MeshRenderer.setModel(id: EntityId, model: ModelHandle?)
-expect fun MeshRenderer.getAllTextureIds(id: EntityId): List<TextureHandle>?
-expect fun MeshRenderer.getMaterialNames(id: EntityId): List<String>
-expect fun MeshRenderer.setMaterialNames(id: EntityId, names: Array<String>)
-expect fun MeshRenderer.getTexture(id: EntityId, materialName: String): Long
-expect fun MeshRenderer.setTextureOverride(id: EntityId, materialName: String, textureHandle: Long)
-
-expect fun meshRendererExistsForEntity(entityId: EntityId): Boolean
diff --git a/src/commonMain/kotlin/com/dropbear/asset/AssetHandle.kt b/src/commonMain/kotlin/com/dropbear/asset/AssetHandle.kt
index e6b31b1..53fb47f 100644
--- a/src/commonMain/kotlin/com/dropbear/asset/AssetHandle.kt
+++ b/src/commonMain/kotlin/com/dropbear/asset/AssetHandle.kt
@@ -24,16 +24,20 @@ class AssetHandle(private val id: Long): Handle(id) {
         return this
     }
 
+    /**
+     * Converts an [AssetHandle] to a [TextureHandle].
+     *
+     * It can return null if the asset is not a texture.
+     */
+    fun asTextureHandle(): TextureHandle? {
+        return if (isTextureHandle(id)) TextureHandle(id) else null
+    }
+
     override fun toString(): String {
         return "AssetHandle(id=$id)"
     }
 }
 
-/**
- * Converts an [AssetHandle] to a [TextureHandle].
- *
- * It can return null if the asset is not a texture.
- */
-expect fun AssetHandle.asTextureHandle(): TextureHandle?
 
+expect fun isTextureHandle(id: Long): Boolean
 expect fun isModelHandle(id: Long): Boolean
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/asset/Handle.kt b/src/commonMain/kotlin/com/dropbear/asset/Handle.kt
index 0528615..57f134c 100644
--- a/src/commonMain/kotlin/com/dropbear/asset/Handle.kt
+++ b/src/commonMain/kotlin/com/dropbear/asset/Handle.kt
@@ -5,8 +5,14 @@ package com.dropbear.asset
  *
  * Aims to allow people to group up different handle types ([AssetHandle], [ModelHandle] etc...)
  * into a list or a vector.
+ *
+ * All handles must be positive, non-zero values. If the id does not follow that rule, it is considered invalid.
  */
 abstract class Handle(private val id: Long) {
+    init {
+        require(id > 0) { "Handle id must be a positive, non-zero value. Got: $id" }
+    }
+
     /**
      * Returns the raw id of the handle
      */
diff --git a/src/commonMain/kotlin/com/dropbear/asset/TextureHandle.kt b/src/commonMain/kotlin/com/dropbear/asset/TextureHandle.kt
index c542985..6690a1e 100644
--- a/src/commonMain/kotlin/com/dropbear/asset/TextureHandle.kt
+++ b/src/commonMain/kotlin/com/dropbear/asset/TextureHandle.kt
@@ -1,7 +1,5 @@
 package com.dropbear.asset
 
-import com.dropbear.DropbearEngine
-
 /**
  * Another type of asset handle, this wraps the id into 
  * another form that only texture related functions can use. 
diff --git a/src/commonMain/kotlin/com/dropbear/components/Camera.kt b/src/commonMain/kotlin/com/dropbear/components/Camera.kt
new file mode 100644
index 0000000..737f23a
--- /dev/null
+++ b/src/commonMain/kotlin/com/dropbear/components/Camera.kt
@@ -0,0 +1,91 @@
+package com.dropbear.components
+
+import com.dropbear.EntityId
+import com.dropbear.ecs.Component
+import com.dropbear.ecs.ComponentType
+import com.dropbear.math.Vector3d
+
+/**
+ * Describes a 3D camera, as defined in `dropbear_engine::camera::Camera`
+ */
+class Camera(
+    internal val entity: EntityId,
+): Component(entity, "Camera3D") {
+    var eye: Vector3d
+        get() = getCameraEye(entity)
+        set(value) = setCameraEye(entity, value)
+    var target: Vector3d
+        get() = getCameraTarget(entity)
+        set(value) = setCameraTarget(entity, value)
+    var up: Vector3d
+        get() = getCameraUp(entity)
+        set(value) = setCameraUp(entity, value)
+    val aspect: Double
+        get() = getCameraAspect(entity)
+    var fov_y: Double
+        get() = getCameraFovY(entity)
+        set(value) = setCameraFovY(entity, value)
+    var znear: Double
+        get() = getCameraZNear(entity)
+        set(value) = setCameraZNear(entity, value)
+    var zfar: Double
+        get() = getCameraZFar(entity)
+        set(value) = setCameraZFar(entity, value)
+    var yaw: Double
+        get() = getCameraYaw(entity)
+        set(value) = setCameraYaw(entity, value)
+    var pitch: Double
+        get() = getCameraPitch(entity)
+        set(value) = setCameraPitch(entity, value)
+    var speed: Double
+        get() = getCameraSpeed(entity)
+        set(value) = setCameraSpeed(entity, value)
+    var sensitivity: Double
+        get() = getCameraSensitivity(entity)
+        set(value) = setCameraSensitivity(entity, value)
+
+    override fun toString(): String {
+        return "Camera component of entity $entity \n" +
+                "eye: $eye\n" +
+                "target: $target\n" +
+                "up: $up\n " +
+                "aspect: $aspect \n" +
+                "fov_y: $fov_y \n" +
+                "znear: $znear \n" +
+                "zfar: $zfar \n" +
+                "yaw: $yaw \n" +
+                "pitch: $pitch" +
+                "speed: $speed" +
+                "sensitivity: $sensitivity"
+    }
+
+    companion object : ComponentType<Camera> {
+        override fun get(entityId: EntityId): Camera? {
+            return if (cameraExistsForEntity(entityId)) Camera(entityId) else null
+        }
+    }
+}
+
+expect fun Camera.getCameraEye(entity: EntityId): Vector3d
+expect fun Camera.setCameraEye(entity: EntityId, value: Vector3d)
+expect fun Camera.getCameraTarget(entity: EntityId): Vector3d
+expect fun Camera.setCameraTarget(entity: EntityId, value: Vector3d)
+expect fun Camera.getCameraUp(entity: EntityId): Vector3d
+expect fun Camera.setCameraUp(entity: EntityId, value: Vector3d)
+expect fun Camera.getCameraAspect(entity: EntityId): Double
+expect fun Camera.getCameraFovY(entity: EntityId): Double
+expect fun Camera.setCameraFovY(entity: EntityId, value: Double)
+expect fun Camera.getCameraZNear(entity: EntityId): Double
+expect fun Camera.setCameraZNear(entity: EntityId, value: Double)
+expect fun Camera.getCameraZFar(entity: EntityId): Double
+expect fun Camera.setCameraZFar(entity: EntityId, value: Double)
+expect fun Camera.getCameraYaw(entity: EntityId): Double
+expect fun Camera.setCameraYaw(entity: EntityId, value: Double)
+expect fun Camera.getCameraPitch(entity: EntityId): Double
+expect fun Camera.setCameraPitch(entity: EntityId, value: Double)
+expect fun Camera.getCameraSpeed(entity: EntityId): Double
+expect fun Camera.setCameraSpeed(entity: EntityId, value: Double)
+expect fun Camera.getCameraSensitivity(entity: EntityId): Double
+expect fun Camera.setCameraSensitivity(entity: EntityId, value: Double)
+
+expect fun cameraExistsForEntity(entity: EntityId): Boolean
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/components/CustomProperties.kt b/src/commonMain/kotlin/com/dropbear/components/CustomProperties.kt
new file mode 100644
index 0000000..3aef136
--- /dev/null
+++ b/src/commonMain/kotlin/com/dropbear/components/CustomProperties.kt
@@ -0,0 +1,99 @@
+package com.dropbear.components
+
+import com.dropbear.EntityId
+import com.dropbear.ecs.Component
+import com.dropbear.ecs.ComponentType
+import com.dropbear.math.Vector3d
+import com.dropbear.math.Vector3f
+import com.dropbear.math.Vector3i
+
+class CustomProperties(val id: EntityId): Component(id, "CustomProperties") {
+    /**
+     * Fetches the property of the ModelProperty component on the entity.
+     *
+     * @param T The type of the property to fetch.
+     * # Supported types
+     * - [kotlin.String]
+     * - [Long]
+     * - [Int]
+     * - [Double]
+     * - [Float]
+     * - [Boolean]
+     * - [Vector3d]
+     * - [Vector3f]
+     * - [Vector3i]
+     * @param key The key of the property to fetch.
+     * @return The property value, or null if the property does not exist.
+     * @throws IllegalArgumentException if the property type is not supported.
+     */
+    inline fun <reified T> getProperty(key: String): T? {
+        return when (T::class) {
+            String::class -> getStringProperty(id.raw, key) as T?
+            Long::class -> getLongProperty(id.raw, key) as T?
+            Int::class -> getIntProperty(id.raw, key) as T?
+            Double::class -> getDoubleProperty(id.raw, key) as T?
+
+            Float::class -> getFloatProperty(id.raw, key) as T?
+            Boolean::class -> getBoolProperty(id.raw, key) as T?
+            Vector3d::class -> getVec3Property(id.raw, key) as T?
+            Vector3f::class -> getVec3Property(id.raw, key)?.toFloat() as T?
+            Vector3i::class -> getVec3Property(id.raw, key)?.toInt() as T?
+            else -> throw IllegalArgumentException("Unsupported property type: ${T::class}")
+        }
+    }
+
+    /**
+     * Sets a property of the ModelProperty component on the entity.
+     *
+     * @param key The key of the property to set.
+     * @param value The type of the property to set.
+     * # Supported types
+     * - [kotlin.String]
+     * - [Long]
+     * - [Int]
+     * - [Double]
+     * - [Float]
+     * - [Boolean]
+     * - [Vector3d]
+     * - [Vector3f]
+     * - [Vector3i]
+     * @throws IllegalArgumentException if the property type is not supported.
+     */
+    fun setProperty(key: String, value: Any) {
+        when (value) {
+            is String -> setStringProperty(id.raw, key, value)
+            is Long -> setLongProperty(id.raw, key, value)
+            is Int -> setIntProperty(id.raw, key, value)
+            is Double -> setFloatProperty(id.raw, key, value)
+            is Float -> setFloatProperty(id.raw, key, value.toDouble())
+            is Boolean -> setBoolProperty(id.raw, key, value)
+            is Vector3d -> setVec3Property(id.raw, key, value)
+            is Vector3f -> setVec3Property(id.raw ,key, value.toDouble())
+            is Vector3i -> setVec3Property(id.raw, key, value.toDouble())
+            else -> throw IllegalArgumentException("Unsupported property type: ${value::class}")
+        }
+    }
+
+    companion object : ComponentType<CustomProperties> {
+        override fun get(entityId: EntityId): CustomProperties? {
+            return if (customPropertiesExistsForEntity(entityId)) CustomProperties(entityId) else null
+        }
+    }
+}
+
+expect fun CustomProperties.getStringProperty(entityHandle: Long, label: String): String?
+expect fun CustomProperties.getIntProperty(entityHandle: Long, label: String): Int?
+expect fun CustomProperties.getLongProperty(entityHandle: Long, label: String): Long?
+expect fun CustomProperties.getDoubleProperty(entityHandle: Long, label: String): Double?
+expect fun CustomProperties.getFloatProperty(entityHandle: Long, label: String): Float?
+expect fun CustomProperties.getBoolProperty(entityHandle: Long, label: String): Boolean?
+expect fun CustomProperties.getVec3Property(entityHandle: Long, label: String): Vector3d?
+
+expect fun CustomProperties.setStringProperty(entityHandle: Long, label: String, value: String)
+expect fun CustomProperties.setIntProperty(entityHandle: Long, label: String, value: Int)
+expect fun CustomProperties.setLongProperty(entityHandle: Long, label: String, value: Long)
+expect fun CustomProperties.setFloatProperty(entityHandle: Long, label: String, value: Double)
+expect fun CustomProperties.setBoolProperty(entityHandle: Long, label: String, value: Boolean)
+expect fun CustomProperties.setVec3Property(entityHandle: Long, label: String, value: Vector3d)
+
+expect fun customPropertiesExistsForEntity(entityId: EntityId): Boolean
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/components/EntityTransform.kt b/src/commonMain/kotlin/com/dropbear/components/EntityTransform.kt
new file mode 100644
index 0000000..3bfb6dd
--- /dev/null
+++ b/src/commonMain/kotlin/com/dropbear/components/EntityTransform.kt
@@ -0,0 +1,60 @@
+package com.dropbear.components
+
+import com.dropbear.EntityId
+import com.dropbear.ecs.Component
+import com.dropbear.ecs.ComponentType
+import com.dropbear.math.Transform
+
+/**
+ * A component that contains the local and world [Transform] of an entity.
+ */
+class EntityTransform(val id: EntityId): Component(id, "EntityTransform") {
+    var local: Transform
+        get() = getLocalTransform(id)
+        set(value) = setLocalTransform(id, value)
+    var world: Transform
+        get() = getWorldTransform(id)
+        set(value) = setWorldTransform(id, value)
+
+    override fun toString(): String {
+        return "EntityTransform(id: $id, local=$local, world=$world)"
+    }
+
+    /**
+     * Walks up the world hierarchy to find the transform of the parent, then multiply/add
+     * to create a propagated [Transform].
+     */
+    fun propagate(): Transform {
+        return propagateTransform(id)
+    }
+
+    /**
+     * Merges the local and world transforms and return the merged [Transform]
+     */
+    fun sync(): Transform {
+        val scaledPos = local.position * world.scale
+        val rotatedPos = world.rotation * scaledPos
+        val finalPos = world.position + rotatedPos
+        val finalRot = world.rotation * local.rotation
+        val finalScale = world.scale * local.scale
+        return Transform(finalPos, finalRot, finalScale)
+    }
+
+    companion object : ComponentType<EntityTransform> {
+        override fun get(entityId: EntityId): EntityTransform? {
+            return if (entityTransformExistsForEntity(entityId)) {
+                EntityTransform(entityId)
+            } else {
+                null
+            }
+        }
+    }
+}
+
+expect fun EntityTransform.getLocalTransform(entityId: EntityId): Transform
+expect fun EntityTransform.setLocalTransform(entityId: EntityId, transform: Transform)
+expect fun EntityTransform.getWorldTransform(entityId: EntityId): Transform
+expect fun EntityTransform.setWorldTransform(entityId: EntityId, transform: Transform)
+expect fun EntityTransform.propagateTransform(entityId: EntityId): Transform
+
+expect fun entityTransformExistsForEntity(entityId: EntityId): Boolean
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/components/MeshRenderer.kt b/src/commonMain/kotlin/com/dropbear/components/MeshRenderer.kt
new file mode 100644
index 0000000..1b826e4
--- /dev/null
+++ b/src/commonMain/kotlin/com/dropbear/components/MeshRenderer.kt
@@ -0,0 +1,64 @@
+package com.dropbear.components
+
+import com.dropbear.EntityId
+import com.dropbear.asset.ModelHandle
+import com.dropbear.asset.TextureHandle
+import com.dropbear.ecs.Component
+import com.dropbear.ecs.ComponentType
+
+class MeshRenderer(val id: EntityId) : Component(id, "MeshRenderer") {
+
+    /**
+     * The active model currently assigned to this entity.
+     * Setting this to null removes the model.
+     *
+     * Usage:
+     * ```
+     * val handle = renderer.model
+     * renderer.model = newHandle
+     * ```
+     */
+    var model: ModelHandle?
+        get() {
+            return getModel(id)
+        }
+        set(value) {
+            setModel(id, value)
+        }
+
+    /**
+     * A list of all active Texture handles currently applied to the model.
+     */
+    val textures: List<TextureHandle>?
+        get() = getAllTextureIds(id)
+
+    /**
+     * Fetches the texture assigned to a specific material slot.
+     * Returns null if the material doesn't exist or has no texture.
+     */
+    fun getTexture(materialName: String): TextureHandle? {
+        val rawId = getTexture(id, materialName)
+        return if (rawId == 0L) null else TextureHandle(rawId)
+    }
+
+    /**
+     * Overrides the texture for a specific material on the active model.
+     */
+    fun setTextureOverride(materialName: String, textureHandle: TextureHandle) {
+        setTextureOverride(id, materialName, textureHandle.raw())
+    }
+
+    companion object : ComponentType<MeshRenderer> {
+        override fun get(entityId: EntityId): MeshRenderer? {
+            return if (meshRendererExistsForEntity(entityId)) MeshRenderer(entityId) else null
+        }
+    }
+}
+
+expect fun MeshRenderer.getModel(id: EntityId): ModelHandle?
+expect fun MeshRenderer.setModel(id: EntityId, model: ModelHandle?)
+expect fun MeshRenderer.getAllTextureIds(id: EntityId): List<TextureHandle>?
+expect fun MeshRenderer.getTexture(id: EntityId, materialName: String): Long
+expect fun MeshRenderer.setTextureOverride(id: EntityId, materialName: String, textureHandle: Long)
+
+expect fun meshRendererExistsForEntity(entityId: EntityId): Boolean
diff --git a/src/commonMain/kotlin/com/dropbear/input/Gamepad.kt b/src/commonMain/kotlin/com/dropbear/input/Gamepad.kt
index 7664888..c15f325 100644
--- a/src/commonMain/kotlin/com/dropbear/input/Gamepad.kt
+++ b/src/commonMain/kotlin/com/dropbear/input/Gamepad.kt
@@ -1,23 +1,28 @@
 package com.dropbear.input
 
 import com.dropbear.ffi.NativeEngine
-import com.dropbear.math.Vector2D
+import com.dropbear.math.Vector2d
 
 /**
  * Information about a specific gamepad for that time in frame.
  */
 class Gamepad(
     val id: Long,
-    val leftStickPosition: Vector2D,
-    val rightStickPosition: Vector2D,
 ) {
+    val leftStickPosition: Vector2d
+        get() = getLeftStickPosition(id)
+    val rightStickPosition: Vector2d
+        get() = getRightStickPosition(id)
+
     fun isButtonPressed(button: GamepadButton): Boolean {
         return isGamepadButtonPressed(id, button)
     }
 
     override fun toString(): String {
-        return "Gamepad $id @ ($leftStickPosition ; $rightStickPosition)"
+        return "Gamepad(id=$id)"
     }
 }
 
-expect fun Gamepad.isGamepadButtonPressed(id: Long, button: GamepadButton): Boolean
\ No newline at end of file
+expect fun Gamepad.isGamepadButtonPressed(id: Long, button: GamepadButton): Boolean
+expect fun Gamepad.getLeftStickPosition(id: Long): Vector2d
+expect fun Gamepad.getRightStickPosition(id: Long): Vector2d
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/input/InputState.kt b/src/commonMain/kotlin/com/dropbear/input/InputState.kt
index fd06c75..5a29d91 100644
--- a/src/commonMain/kotlin/com/dropbear/input/InputState.kt
+++ b/src/commonMain/kotlin/com/dropbear/input/InputState.kt
@@ -1,8 +1,6 @@
 package com.dropbear.input
 
-import com.dropbear.DropbearEngine
-import com.dropbear.ffi.NativeEngine
-import com.dropbear.math.Vector2D
+import com.dropbear.math.Vector2d
 
 /**
  * The current state of the input system.
@@ -16,12 +14,12 @@ import com.dropbear.math.Vector2D
 expect class InputState() {
     fun printInputState()
     fun isKeyPressed(key: KeyCode): Boolean
-    fun getMousePosition(): Vector2D
+    fun getMousePosition(): Vector2d
     fun isMouseButtonPressed(button: MouseButton): Boolean
-    fun getMouseDelta(): Vector2D
+    fun getMouseDelta(): Vector2d
     fun isCursorLocked(): Boolean
     fun setCursorLocked(locked: Boolean)
-    fun getLastMousePos(): Vector2D
+    fun getLastMousePos(): Vector2d
     fun isCursorHidden(): Boolean
     fun setCursorHidden(hidden: Boolean)
     fun getConnectedGamepads(): List<Gamepad>
diff --git a/src/commonMain/kotlin/com/dropbear/math/Quaternion.kt b/src/commonMain/kotlin/com/dropbear/math/Quaternion.kt
index 9e1cae3..3cddb8a 100644
--- a/src/commonMain/kotlin/com/dropbear/math/Quaternion.kt
+++ b/src/commonMain/kotlin/com/dropbear/math/Quaternion.kt
@@ -1,18 +1,12 @@
 package com.dropbear.math
 
 import kotlin.jvm.JvmField
-import kotlin.math.PI
-import kotlin.math.acos
-import kotlin.math.asin
-import kotlin.math.atan2
-import kotlin.math.cos
-import kotlin.math.max
-import kotlin.math.min
-import kotlin.math.sin
-import kotlin.math.sqrt
-
-typealias QuaternionD = Quaternion<Double>
+import kotlin.jvm.JvmStatic
 
+/**
+ * Generic Quaternion wrapper.
+ * WARNING: Uses boxing. Prefer [Quaterniond]/[Quaternionf] for performance.
+ */
 class Quaternion<T: Number>(
     @JvmField var x: T,
     @JvmField var y: T,
@@ -20,322 +14,34 @@ class Quaternion<T: Number>(
     @JvmField var w: T
 ) {
     companion object {
-        fun identity(): QuaternionD {
-            return Quaternion(0.0, 0.0, 0.0, 1.0)
-        }
-
-        fun fromEulerAngles(pitch: Double, yaw: Double, roll: Double): QuaternionD {
-            val halfPitch = pitch * 0.5
-            val halfYaw = yaw * 0.5
-            val halfRoll = roll * 0.5
-            val sp = sin(halfPitch)
-            val cp = cos(halfPitch)
-            val sy = sin(halfYaw)
-            val cy = cos(halfYaw)
-            val sr = sin(halfRoll)
-            val cr = cos(halfRoll)
-
-            return Quaternion(
-                x = cy * sr * cp - sy * cr * sp,
-                y = sy * cr * cp + cy * sr * sp,
-                z = sy * sr * cp - cy * cr * sp,
-                w = cy * cr * cp + sy * sr * sp
-            )
-        }
-
-        fun fromAxisAngle(axis: Vector3<Double>, angleRadians: Double): QuaternionD {
-            val normalizedAxis = axis.normalizedCopy()
-            val halfAngle = angleRadians * 0.5
-            val sinHalf = sin(halfAngle)
-            return Quaternion(
-                normalizedAxis.x * sinHalf,
-                normalizedAxis.y * sinHalf,
-                normalizedAxis.z * sinHalf,
-                cos(halfAngle)
-            )
-        }
-
-        fun rotateX(angleRadians: Double): QuaternionD {
-            return fromAxisAngle(Vector3D(1.0, 0.0, 0.0), angleRadians)
-        }
-
-        fun rotateY(angleRadians: Double): QuaternionD {
-            return fromAxisAngle(Vector3D(0.0, 1.0, 0.0), angleRadians)
-        }
-
-        fun rotateZ(angleRadians: Double): QuaternionD {
-            return fromAxisAngle(Vector3D(0.0, 0.0, 1.0), angleRadians)
-        }
-
-        fun fromToRotation(from: Vector3<Double>, to: Vector3<Double>): QuaternionD {
-            val start = from.normalizedCopy()
-            val end = to.normalizedCopy()
-            val dot = (start.x * end.x) + (start.y * end.y) + (start.z * end.z)
-            if (dot >= 1.0 - 1e-6) {
-                return identity()
-            }
-            if (dot <= -1.0 + 1e-6) {
-                val orthogonal = if (kotlin.math.abs(start.x) < 0.9) {
-                    Vector3D(1.0, 0.0, 0.0)
-                } else {
-                    Vector3D(0.0, 1.0, 0.0)
-                }
-                val axis = start.cross(orthogonal).normalizedCopy()
-                return fromAxisAngle(axis, PI)
-            }
-            val axis = start.cross(end)
-            val angle = acos(dot.coerceIn(-1.0, 1.0))
-            return fromAxisAngle(axis, angle)
-        }
-    }
-
-    fun <T : Number> rotateX(angleRadians: T): Quaternion<T> {
-        val halfAngle = angleRadians.toDouble() * 0.5
-        @Suppress("UNCHECKED_CAST")
-        return Quaternion(sin(halfAngle), 0.0, 0.0, cos(halfAngle)) as Quaternion<T>
-    }
-
-    fun <T: Number> rotateY(angleRadians: T): Quaternion<T> {
-        val halfAngle = angleRadians.toDouble() * 0.5
-        @Suppress("UNCHECKED_CAST")
-        return Quaternion(0.0, sin(halfAngle), 0.0, cos(halfAngle)) as Quaternion<T>
-    }
-
-    fun <T: Number> rotateZ(angleRadians: T): Quaternion<T> {
-        val halfAngle = angleRadians.toDouble() * 0.5
-        @Suppress("UNCHECKED_CAST")
-        return Quaternion(0.0, 0.0, sin(halfAngle), cos(halfAngle)) as Quaternion<T>
-    }
-
-    fun asDoubleQuaternion(): QuaternionD {
-        return Quaternion(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble())
-    }
-
-    fun conjugate(): QuaternionD {
-        return Quaternion(-x.toDouble(), -y.toDouble(), -z.toDouble(), w.toDouble())
-    }
-
-    fun dot(other: Quaternion<*>): Double {
-        return x.toDouble() * other.x.toDouble() +
-                y.toDouble() * other.y.toDouble() +
-                z.toDouble() * other.z.toDouble() +
-                w.toDouble() * other.w.toDouble()
-    }
-
-    fun lengthSquared(): Double {
-        return dot(this)
-    }
-
-    fun length(): Double {
-        return sqrt(lengthSquared())
-    }
-
-    fun isNormalized(epsilon: Double = 1e-6): Boolean {
-        return kotlin.math.abs(length() - 1.0) <= epsilon
-    }
-
-    fun normalized(): QuaternionD {
-        val len = length()
-        if (len == 0.0) {
-            return identity()
-        }
-        val invLen = 1.0 / len
-        return Quaternion(
-            x.toDouble() * invLen,
-            y.toDouble() * invLen,
-            z.toDouble() * invLen,
-            w.toDouble() * invLen
-        )
-    }
-
-    fun normalizeInPlace(): Quaternion<T> {
-        val normalized = normalized()
-        @Suppress("UNCHECKED_CAST")
-        x = normalized.x as T
-        @Suppress("UNCHECKED_CAST")
-        y = normalized.y as T
-        @Suppress("UNCHECKED_CAST")
-        z = normalized.z as T
-        @Suppress("UNCHECKED_CAST")
-        w = normalized.w as T
-        return this
-    }
-
-    operator fun <R: Number> plus(other: Quaternion<R>): QuaternionD {
-        return Quaternion(
-            x.toDouble() + other.x.toDouble(),
-            y.toDouble() + other.y.toDouble(),
-            z.toDouble() + other.z.toDouble(),
-            w.toDouble() + other.w.toDouble()
-        )
-    }
-
-    operator fun <R: Number> minus(other: Quaternion<R>): QuaternionD {
-        return Quaternion(
-            x.toDouble() - other.x.toDouble(),
-            y.toDouble() - other.y.toDouble(),
-            z.toDouble() - other.z.toDouble(),
-            w.toDouble() - other.w.toDouble()
-        )
-    }
-
-    operator fun unaryMinus(): QuaternionD {
-        return Quaternion(-x.toDouble(), -y.toDouble(), -z.toDouble(), -w.toDouble())
-    }
-
-    operator fun times(scalar: Number): QuaternionD {
-        val value = scalar.toDouble()
-        return Quaternion(
-            x.toDouble() * value,
-            y.toDouble() * value,
-            z.toDouble() * value,
-            w.toDouble() * value
-        )
-    }
-
-    operator fun div(scalar: Number): QuaternionD {
-        val value = scalar.toDouble()
-        require(value != 0.0) { "Cannot divide Quaternion by zero." }
-        val inv = 1.0 / value
-        return Quaternion(
-            x.toDouble() * inv,
-            y.toDouble() * inv,
-            z.toDouble() * inv,
-            w.toDouble() * inv
-        )
-    }
-
-    operator fun <R: Number> times(other: Quaternion<R>): QuaternionD {
-        val ax = x.toDouble()
-        val ay = y.toDouble()
-        val az = z.toDouble()
-        val aw = w.toDouble()
-        val bx = other.x.toDouble()
-        val by = other.y.toDouble()
-        val bz = other.z.toDouble()
-        val bw = other.w.toDouble()
-        return Quaternion(
-            aw * bx + ax * bw + ay * bz - az * by,
-            aw * by - ax * bz + ay * bw + az * bx,
-            aw * bz + ax * by - ay * bx + az * bw,
-            aw * bw - ax * bx - ay * by - az * bz
-        )
-    }
-
-    fun inverse(): QuaternionD {
-        val lenSq = lengthSquared()
-        if (lenSq == 0.0) {
-            return identity()
-        }
-        val conjugate = conjugate()
-        val inv = 1.0 / lenSq
-        return Quaternion(
-            conjugate.x * inv,
-            conjugate.y * inv,
-            conjugate.z * inv,
-            conjugate.w * inv
-        )
-    }
+        @JvmStatic
+        fun identity(): Quaternion<Double> = Quaternion(0.0, 0.0, 0.0, 1.0)
 
-    fun rotate(vector: Vector3<T>): Vector3<Double> {
-        val doubleVector = vector.asDoubleVector()
-        val vectorQuat = Quaternion(doubleVector.x, doubleVector.y, doubleVector.z, 0.0)
-        val rotated = (this * vectorQuat) * conjugate()
-        return Vector3(rotated.x, rotated.y, rotated.z)
-    }
-
-    operator fun times(vector: Vector3<T>): Vector3<Double> {
-        return rotate(vector)
-    }
-
-    fun nlerp(other: Quaternion<*>, t: Double): QuaternionD {
-        val alpha = t.coerceIn(0.0, 1.0)
-        val inverse = 1.0 - alpha
-        return Quaternion(
-            x.toDouble() * inverse + other.x.toDouble() * alpha,
-            y.toDouble() * inverse + other.y.toDouble() * alpha,
-            z.toDouble() * inverse + other.z.toDouble() * alpha,
-            w.toDouble() * inverse + other.w.toDouble() * alpha
-        ).normalized()
-    }
-
-    fun slerp(other: Quaternion<*>, t: Double): QuaternionD {
-        val alpha = t.coerceIn(0.0, 1.0)
-        var q1 = normalized()
-        var q2 = Quaternion(
-            other.x.toDouble(),
-            other.y.toDouble(),
-            other.z.toDouble(),
-            other.w.toDouble()
-        ).normalized()
-
-        var dot = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w
-        if (dot < 0.0) {
-            dot = -dot
-            q2 = Quaternion(-q2.x, -q2.y, -q2.z, -q2.w)
-        }
-
-        dot = min(1.0, max(-1.0, dot))
-
-        if (dot > 0.9995) {
-            return Quaternion(
-                q1.x + alpha * (q2.x - q1.x),
-                q1.y + alpha * (q2.y - q1.y),
-                q1.z + alpha * (q2.z - q1.z),
-                q1.w + alpha * (q2.w - q1.w)
-            ).normalized()
+        @JvmStatic
+        fun fromEulerAngles(pitch: Double, yaw: Double, roll: Double): Quaternion<Double> {
+            return Quaterniond.fromEulerAngles(pitch, yaw, roll).toGeneric()
         }
-
-        val theta0 = acos(dot)
-        val sinTheta0 = sin(theta0)
-        val theta = theta0 * alpha
-        val sinTheta = sin(theta)
-        val s0 = cos(theta) - dot * sinTheta / sinTheta0
-        val s1 = sinTheta / sinTheta0
-
-        return Quaternion(
-            q1.x * s0 + q2.x * s1,
-            q1.y * s0 + q2.y * s1,
-            q1.z * s0 + q2.z * s1,
-            q1.w * s0 + q2.w * s1
-        ).normalized()
     }
 
-    fun toEulerAngles(): Vector3D {
-        val q = normalized()
-        val xx = q.x * q.x
-        val yy = q.y * q.y
-        val zz = q.z * q.z
-
-        val sinPitch = 2.0 * (q.w * q.x - q.y * q.z)
-        val pitch = asin(max(-1.0, min(1.0, sinPitch)))
-
-        val sinYaw = 2.0 * (q.w * q.y + q.z * q.x)
-        val cosYaw = 1.0 - 2.0 * (xx + zz)
-        val yaw = atan2(sinYaw, cosYaw)
+    fun asQuaterniond() = Quaterniond(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble())
+    fun asQuaternionf() = Quaternionf(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat())
 
-        val sinRoll = 2.0 * (q.w * q.z + q.x * q.y)
-        val cosRoll = 1.0 - 2.0 * (yy + xx)
-        val roll = atan2(sinRoll, cosRoll)
+    fun normalize(): Quaternion<Double> = asQuaterniond().normalize().toGeneric()
+    fun inverse(): Quaternion<Double> = asQuaterniond().inverse().toGeneric()
 
-        return Vector3D(pitch, yaw, roll)
-    }
-
-    fun toAxisAngle(): Pair<Vector3D, Double> {
-        val q = normalized()
-        val angle = 2.0 * acos(q.w)
-        val sinHalfAngle = sqrt(1.0 - q.w * q.w)
-        if (sinHalfAngle < 1e-6) {
-            return Vector3D(1.0, 0.0, 0.0) to angle
-        }
-        return Vector3D(q.x / sinHalfAngle, q.y / sinHalfAngle, q.z / sinHalfAngle) to angle
-    }
+    override fun toString() = "Quaternion($x, $y, $z, $w)"
 
-    fun toVector4(): Vector4<Double> {
-        return Vector4(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble())
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is Quaternion<*>) return false
+        return x == other.x && y == other.y && z == other.z && w == other.w
     }
 
-    override fun toString(): String {
-        return "Quaternion(x=$x, y=$y, z=$z, w=$w)"
+    override fun hashCode(): Int {
+        var result = x.hashCode()
+        result = 31 * result + y.hashCode()
+        result = 31 * result + z.hashCode()
+        result = 31 * result + w.hashCode()
+        return result
     }
 }
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/math/Quaterniond.kt b/src/commonMain/kotlin/com/dropbear/math/Quaterniond.kt
new file mode 100644
index 0000000..3fcab97
--- /dev/null
+++ b/src/commonMain/kotlin/com/dropbear/math/Quaterniond.kt
@@ -0,0 +1,183 @@
+package com.dropbear.math
+
+import kotlin.jvm.JvmField
+import kotlin.jvm.JvmStatic
+import kotlin.math.*
+
+class Quaterniond(
+    @JvmField var x: Double,
+    @JvmField var y: Double,
+    @JvmField var z: Double,
+    @JvmField var w: Double
+) {
+    companion object {
+        @JvmStatic fun identity() = Quaterniond(0.0, 0.0, 0.0, 1.0)
+
+        @JvmStatic
+        fun fromEulerAngles(pitch: Double, yaw: Double, roll: Double): Quaterniond {
+            val halfPitch = pitch * 0.5
+            val halfYaw = yaw * 0.5
+            val halfRoll = roll * 0.5
+            val sp = sin(halfPitch)
+            val cp = cos(halfPitch)
+            val sy = sin(halfYaw)
+            val cy = cos(halfYaw)
+            val sr = sin(halfRoll)
+            val cr = cos(halfRoll)
+
+            return Quaterniond(
+                x = cy * sr * cp - sy * cr * sp,
+                y = sy * cr * cp + cy * sr * sp,
+                z = sy * sr * cp - cy * cr * sp,
+                w = cy * cr * cp + sy * sr * sp
+            )
+        }
+
+        @JvmStatic
+        fun fromAxisAngle(axis: Vector3d, angleRadians: Double): Quaterniond {
+            val normalizedAxis = axis.normalize()
+            val halfAngle = angleRadians * 0.5
+            val sinHalf = sin(halfAngle)
+            return Quaterniond(
+                normalizedAxis.x * sinHalf,
+                normalizedAxis.y * sinHalf,
+                normalizedAxis.z * sinHalf,
+                cos(halfAngle)
+            )
+        }
+
+        @JvmStatic fun rotateX(angle: Double) = fromAxisAngle(Vector3d(1.0, 0.0, 0.0), angle)
+        @JvmStatic fun rotateY(angle: Double) = fromAxisAngle(Vector3d(0.0, 1.0, 0.0), angle)
+        @JvmStatic fun rotateZ(angle: Double) = fromAxisAngle(Vector3d(0.0, 0.0, 1.0), angle)
+
+        @JvmStatic
+        fun fromToRotation(from: Vector3d, to: Vector3d): Quaterniond {
+            val start = from.normalize()
+            val end = to.normalize()
+            val dot = start.dot(end)
+
+            if (dot >= 1.0 - 1e-6) return identity()
+            if (dot <= -1.0 + 1e-6) {
+                val orthogonal = if (abs(start.x) < 0.9) Vector3d(1.0, 0.0, 0.0) else Vector3d(0.0, 1.0, 0.0)
+                val axis = start.cross(orthogonal).normalize()
+                return fromAxisAngle(axis, PI)
+            }
+            val axis = start.cross(end)
+            val angle = acos(dot.coerceIn(-1.0, 1.0))
+            return fromAxisAngle(axis, angle)
+        }
+
+        private fun copySign(magnitude: Double, sign: Double): Double {
+            val absMag = abs(magnitude)
+            return if (sign < 0.0) -absMag else absMag
+        }
+    }
+
+    operator fun plus(other: Quaterniond) = Quaterniond(x + other.x, y + other.y, z + other.z, w + other.w)
+    operator fun minus(other: Quaterniond) = Quaterniond(x - other.x, y - other.y, z - other.z, w - other.w)
+    operator fun unaryMinus() = Quaterniond(-x, -y, -z, -w)
+
+    operator fun times(scalar: Double) = Quaterniond(x * scalar, y * scalar, z * scalar, w * scalar)
+    operator fun div(scalar: Double) = Quaterniond(x / scalar, y / scalar, z / scalar, w / scalar)
+
+    /**
+     * Quaternion Multiplication (Composition).
+     * Represents applying rotation `other`, then rotation `this`.
+     */
+    operator fun times(other: Quaterniond): Quaterniond {
+        return Quaterniond(
+            w * other.x + x * other.w + y * other.z - z * other.y,
+            w * other.y - x * other.z + y * other.w + z * other.x,
+            w * other.z + x * other.y - y * other.x + z * other.w,
+            w * other.w - x * other.x - y * other.y - z * other.z
+        )
+    }
+
+    /**
+     * Rotates a vector by this quaternion.
+     */
+    operator fun times(vector: Vector3d): Vector3d {
+        val qVec = Vector3d(x, y, z)
+        val uv = qVec.cross(vector)
+        val uuv = qVec.cross(uv)
+        return vector + ((uv * w) + uuv) * 2.0
+    }
+
+    fun dot(other: Quaterniond) = x * other.x + y * other.y + z * other.z + w * other.w
+    fun lengthSquared() = x * x + y * y + z * z + w * w
+    fun length() = sqrt(lengthSquared())
+
+    fun normalize(): Quaterniond {
+        val len = length()
+        return if (len == 0.0) identity() else this / len
+    }
+
+    fun inverse(): Quaterniond {
+        val lenSq = lengthSquared()
+        if (lenSq == 0.0) return identity()
+        val inv = 1.0 / lenSq
+        return Quaterniond(-x * inv, -y * inv, -z * inv, w * inv)
+    }
+
+    fun conjugate() = Quaterniond(-x, -y, -z, w)
+
+    fun slerp(other: Quaterniond, t: Double): Quaterniond {
+        val alpha = t.coerceIn(0.0, 1.0)
+        var q1 = this.normalize()
+        var q2 = other.normalize()
+
+        var dot = q1.dot(q2)
+
+        if (dot < 0.0) {
+            dot = -dot
+            q2 = -q2
+        }
+
+        if (dot > 0.9995) {
+            return (q1 + (q2 - q1) * alpha).normalize()
+        }
+
+        val theta0 = acos(dot)
+        val theta = theta0 * alpha
+        val sinTheta = sin(theta)
+        val sinTheta0 = sin(theta0)
+
+        val s0 = cos(theta) - dot * sinTheta / sinTheta0
+        val s1 = sinTheta / sinTheta0
+
+        return (q1 * s0) + (q2 * s1)
+    }
+
+    fun toEulerAngles(): Vector3d {
+        val sinr_cosp = 2.0 * (w * z + x * y)
+        val cosr_cosp = 1.0 - 2.0 * (y * y + z * z)
+        val roll = atan2(sinr_cosp, cosr_cosp)
+
+        val sinp = 2.0 * (w * x - y * z)
+        val pitch: Double
+        if (abs(sinp) >= 1.0) {
+            pitch = copySign(PI / 2, sinp)
+        } else {
+            pitch = asin(sinp)
+        }
+
+        val siny_cosp = 2.0 * (w * y + z * x)
+        val cosy_cosp = 1.0 - 2.0 * (x * x + y * y)
+        val yaw = atan2(siny_cosp, cosy_cosp)
+
+        return Vector3d(pitch, yaw, roll)
+    }
+
+    fun toFloat() = Quaternionf(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat())
+    fun toGeneric() = Quaternion(x, y, z, w)
+
+    override fun toString() = "Quaterniond($x, $y, $z, $w)"
+    override fun equals(other: Any?) = other is Quaterniond && x == other.x && y == other.y && z == other.z && w == other.w
+    override fun hashCode(): Int {
+        var result = x.hashCode()
+        result = 31 * result + y.hashCode()
+        result = 31 * result + z.hashCode()
+        result = 31 * result + w.hashCode()
+        return result
+    }
+}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/math/Quaternionf.kt b/src/commonMain/kotlin/com/dropbear/math/Quaternionf.kt
new file mode 100644
index 0000000..0999ca1
--- /dev/null
+++ b/src/commonMain/kotlin/com/dropbear/math/Quaternionf.kt
@@ -0,0 +1,122 @@
+package com.dropbear.math
+
+import kotlin.jvm.JvmField
+import kotlin.jvm.JvmStatic
+import kotlin.math.*
+
+class Quaternionf(
+    @JvmField var x: Float,
+    @JvmField var y: Float,
+    @JvmField var z: Float,
+    @JvmField var w: Float
+) {
+    companion object {
+        @JvmStatic fun identity() = Quaternionf(0f, 0f, 0f, 1f)
+
+        @JvmStatic
+        fun fromEulerAngles(pitch: Float, yaw: Float, roll: Float): Quaternionf {
+            val halfPitch = pitch * 0.5f
+            val halfYaw = yaw * 0.5f
+            val halfRoll = roll * 0.5f
+            val sp = sin(halfPitch)
+            val cp = cos(halfPitch)
+            val sy = sin(halfYaw)
+            val cy = cos(halfYaw)
+            val sr = sin(halfRoll)
+            val cr = cos(halfRoll)
+
+            return Quaternionf(
+                x = cy * sr * cp - sy * cr * sp,
+                y = sy * cr * cp + cy * sr * sp,
+                z = sy * sr * cp - cy * cr * sp,
+                w = cy * cr * cp + sy * sr * sp
+            )
+        }
+
+        @JvmStatic
+        fun fromAxisAngle(axis: Vector3f, angleRadians: Float): Quaternionf {
+            val normalizedAxis = axis.normalize()
+            val halfAngle = angleRadians * 0.5f
+            val sinHalf = sin(halfAngle)
+            return Quaternionf(
+                normalizedAxis.x * sinHalf,
+                normalizedAxis.y * sinHalf,
+                normalizedAxis.z * sinHalf,
+                cos(halfAngle)
+            )
+        }
+
+        @JvmStatic fun rotateX(angle: Float) = fromAxisAngle(Vector3f(1f, 0f, 0f), angle)
+        @JvmStatic fun rotateY(angle: Float) = fromAxisAngle(Vector3f(0f, 1f, 0f), angle)
+        @JvmStatic fun rotateZ(angle: Float) = fromAxisAngle(Vector3f(0f, 0f, 1f), angle)
+
+        private fun copySign(magnitude: Float, sign: Float): Float {
+            val absMag = abs(magnitude)
+            return if (sign < 0f) -absMag else absMag
+        }
+    }
+
+    operator fun plus(other: Quaternionf) = Quaternionf(x + other.x, y + other.y, z + other.z, w + other.w)
+    operator fun minus(other: Quaternionf) = Quaternionf(x - other.x, y - other.y, z - other.z, w - other.w)
+    operator fun unaryMinus() = Quaternionf(-x, -y, -z, -w)
+
+    operator fun times(scalar: Float) = Quaternionf(x * scalar, y * scalar, z * scalar, w * scalar)
+    operator fun div(scalar: Float) = Quaternionf(x / scalar, y / scalar, z / scalar, w / scalar)
+
+    operator fun times(other: Quaternionf): Quaternionf {
+        return Quaternionf(
+            w * other.x + x * other.w + y * other.z - z * other.y,
+            w * other.y - x * other.z + y * other.w + z * other.x,
+            w * other.z + x * other.y - y * other.x + z * other.w,
+            w * other.w - x * other.x - y * other.y - z * other.z
+        )
+    }
+
+    operator fun times(vector: Vector3f): Vector3f {
+        val qVec = Vector3f(x, y, z)
+        val uv = qVec.cross(vector)
+        val uuv = qVec.cross(uv)
+        return vector + ((uv * w) + uuv) * 2f
+    }
+
+    fun dot(other: Quaternionf) = x * other.x + y * other.y + z * other.z + w * other.w
+    fun lengthSquared() = x * x + y * y + z * z + w * w
+    fun length() = sqrt(lengthSquared())
+
+    fun normalize(): Quaternionf {
+        val len = length()
+        return if (len == 0f) identity() else this / len
+    }
+
+    fun inverse(): Quaternionf {
+        val lenSq = lengthSquared()
+        if (lenSq == 0f) return identity()
+        val inv = 1.0f / lenSq
+        return Quaternionf(-x * inv, -y * inv, -z * inv, w * inv)
+    }
+
+    fun conjugate() = Quaternionf(-x, -y, -z, w)
+
+    fun toDouble() = Quaterniond(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble())
+
+    fun toEulerAngles(): Vector3f {
+        val sinr_cosp = 2f * (w * z + x * y)
+        val cosr_cosp = 1f - 2f * (y * y + z * z)
+        val roll = atan2(sinr_cosp, cosr_cosp)
+
+        val sinp = 2f * (w * x - y * z)
+        val pitch = if (abs(sinp) >= 1f) {
+            copySign(PI.toFloat() / 2f, sinp)
+        } else {
+            asin(sinp)
+        }
+
+        val siny_cosp = 2f * (w * y + z * x)
+        val cosy_cosp = 1f - 2f * (x * x + y * y)
+        val yaw = atan2(siny_cosp, cosy_cosp)
+
+        return Vector3f(pitch, yaw, roll)
+    }
+
+    override fun toString() = "Quaternionf($x, $y, $z, $w)"
+}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/math/Transform.kt b/src/commonMain/kotlin/com/dropbear/math/Transform.kt
index e055df1..052889e 100644
--- a/src/commonMain/kotlin/com/dropbear/math/Transform.kt
+++ b/src/commonMain/kotlin/com/dropbear/math/Transform.kt
@@ -5,9 +5,9 @@ package com.dropbear.math
  * attached to an entity. 
  */
 class Transform(
-    var position: Vector3D,
-    var rotation: QuaternionD,
-    var scale: Vector3D
+    var position: Vector3d,
+    var rotation: Quaterniond,
+    var scale: Vector3d
 ) {
     /**
      * Specific constructor for the individual raw primitive values.
@@ -18,9 +18,9 @@ class Transform(
                 rx: Double, ry: Double, rz: Double, rw: Double,
                 sx: Double, sy: Double, sz: Double)
             : this(
-        Vector3D(px, py, pz),
-        QuaternionD(rx, ry, rz, rw),
-        Vector3D(sx, sy, sz)
+        Vector3d(px, py, pz),
+        Quaterniond(rx, ry, rz, rw),
+        Vector3d(sx, sy, sz)
             )
 
     override fun toString(): String {
diff --git a/src/commonMain/kotlin/com/dropbear/math/Vector.kt b/src/commonMain/kotlin/com/dropbear/math/Vector.kt
deleted file mode 100644
index 9674fc3..0000000
--- a/src/commonMain/kotlin/com/dropbear/math/Vector.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.dropbear.math
-
-/**
- * Abstract class all Vectors inherit.
- */
-abstract class Vector<T: Number, SELF: Vector<T, SELF>> {
-    abstract fun normalize(): SELF
-
-    abstract operator fun plus(other: SELF): SELF
-    abstract operator fun plus(scalar: T): SELF
-
-    abstract operator fun minus(other: SELF): SELF
-    abstract operator fun minus(scalar: T): SELF
-
-    abstract operator fun times(other: SELF): SELF
-    abstract operator fun times(scalar: T): SELF
-
-    abstract operator fun div(other: SELF): SELF
-    abstract operator fun div(scalar: T): SELF
-
-    abstract fun length(): Double
-
-    abstract fun copy(): SELF
-}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/math/Vector2.kt b/src/commonMain/kotlin/com/dropbear/math/Vector2.kt
index 1fd31eb..b433269 100644
--- a/src/commonMain/kotlin/com/dropbear/math/Vector2.kt
+++ b/src/commonMain/kotlin/com/dropbear/math/Vector2.kt
@@ -1,180 +1,32 @@
 package com.dropbear.math
 
 import kotlin.jvm.JvmField
-import kotlin.math.sqrt
+import kotlin.jvm.JvmStatic
 
 /**
- * A class for holding a vector of `2` values of the same type.
+ * A Generic Vector2.
+ * WARNING: Uses boxing. Prefer [Vector2d]/[Vector2f]/[Vector2i] for performance.
  */
-class Vector2<T: Number>(
+class Vector2<T : Number>(
     @JvmField var x: T,
-    @JvmField var y: T,
-) : Vector<T, Vector2<T>>() {
+    @JvmField var y: T
+) {
     companion object {
-        /**
-         * Creates a new [com.dropbear.math.Vector2] of type `T` with one value.
-         */
-        fun <T: Number> uniform(value: T): Vector2<T> {
-            return Vector2(value, value)
-        }
-
-        /**
-         * Creates a [com.dropbear.math.Vector2] of type [Double] filled with only zeroes
-         */
-        fun zero(): Vector2<Double> {
-            return Vector2(0.0, 0.0)
-        }
-    }
-
-    fun asDoubleVector(): Vector2<Double> {
-        return Vector2(this.x.toDouble(), this.y.toDouble())
-    }
-
-    override fun normalize(): Vector2<T> {
-        val length = length()
-        if (length > 0.0) {
-            val invLength = 1.0 / length
-            @Suppress("UNCHECKED_CAST")
-            x = (x.toDouble() * invLength) as T
-            @Suppress("UNCHECKED_CAST")
-            y = (y.toDouble() * invLength) as T
-        }
-        return this
-    }
-
-    override operator fun plus(other: Vector2<T>): Vector2<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector2(
-            x.toDouble() + other.x.toDouble(),
-            y.toDouble() + other.y.toDouble()
-        ) as Vector2<T>
-    }
-
-    override operator fun plus(scalar: T): Vector2<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector2(
-            x.toDouble() + scalar.toDouble(),
-            y.toDouble() + scalar.toDouble()
-        ) as Vector2<T>
-    }
-
-    override operator fun minus(other: Vector2<T>): Vector2<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector2(
-            x.toDouble() - other.x.toDouble(),
-            y.toDouble() - other.y.toDouble()
-        ) as Vector2<T>
-    }
-
-    override operator fun minus(scalar: T): Vector2<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector2(
-            x.toDouble() - scalar.toDouble(),
-            y.toDouble() - scalar.toDouble()
-        ) as Vector2<T>
-    }
-
-    override operator fun times(other: Vector2<T>): Vector2<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector2(
-            x.toDouble() * other.x.toDouble(),
-            y.toDouble() * other.y.toDouble()
-        ) as Vector2<T>
-    }
-
-    override operator fun times(scalar: T): Vector2<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector2(
-            x.toDouble() * scalar.toDouble(),
-            y.toDouble() * scalar.toDouble()
-        ) as Vector2<T>
-    }
-
-    override operator fun div(other: Vector2<T>): Vector2<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector2(
-            x.toDouble() / other.x.toDouble(),
-            y.toDouble() / other.y.toDouble()
-        ) as Vector2<T>
-    }
-
-    override operator fun div(scalar: T): Vector2<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector2(
-            x.toDouble() / scalar.toDouble(),
-            y.toDouble() / scalar.toDouble(),
-        ) as Vector2<T>
-    }
-
-    fun lengthSquared(): Double {
-        val dx = x.toDouble()
-        val dy = y.toDouble()
-        return dx * dx + dy * dy
-    }
-
-    fun dot(other: Vector2<T>): Double {
-        return x.toDouble() * other.x.toDouble() + y.toDouble() * other.y.toDouble()
-    }
-
-    fun distanceTo(other: Vector2<T>): Double {
-        val dx = x.toDouble() - other.x.toDouble()
-        val dy = y.toDouble() - other.y.toDouble()
-        return sqrt(dx * dx + dy * dy)
-    }
-
-    fun normalizedCopy(): Vector2<Double> {
-        val length = length()
-        if (length == 0.0) {
-            return zero()
-        }
-        val invLength = 1.0 / length
-        return Vector2(
-            x.toDouble() * invLength,
-            y.toDouble() * invLength
-        )
-    }
-
-    fun lerp(target: Vector2<T>, alpha: Double): Vector2<Double> {
-        val inverse = 1.0 - alpha
-        return Vector2(
-            x.toDouble() * inverse + target.x.toDouble() * alpha,
-            y.toDouble() * inverse + target.y.toDouble() * alpha
-        )
-    }
-
-    operator fun unaryMinus(): Vector2<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector2(-x.toDouble(), -y.toDouble()) as Vector2<T>
-    }
-
-    fun toVector3(z: T): Vector3<T> {
-        return Vector3(x, y, z)
+        @JvmStatic
+        fun fromDoubles(x: Double, y: Double): Vector2<Double> = Vector2(x, y)
     }
 
-    fun toVector4(z: T, w: T): Vector4<T> {
-        return Vector4(x, y, z, w)
-    }
-
-    operator fun component1(): T = x
-    operator fun component2(): T = y
+    fun asVector2d(): Vector2d = Vector2d(x.toDouble(), y.toDouble())
+    fun asVector2f(): Vector2f = Vector2f(x.toFloat(), y.toFloat())
+    fun asVector2i(): Vector2i = Vector2i(x.toInt(), y.toInt())
 
-    /**
-     * Returns the magnitude/length of the vector
-     *
-     * ## Math
-     * `sqrt(x^2 + y^2)`
-     */
-    override fun length(): Double {
-        return sqrt(x.toDouble() * x.toDouble() + y.toDouble() * y.toDouble())
-    }
-
-    override fun copy(): Vector2<T> {
-        return Vector2(x, y)
-    }
+    override fun toString() = "Vector2($x, $y)"
 
-    override fun toString(): String {
-        return "Vector2(x=$x, y=$y)"
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is Vector2<*>) return false
+        return x == other.x && y == other.y
     }
-}
 
-typealias Vector2D = Vector2<Double>
\ No newline at end of file
+    override fun hashCode() = 31 * x.hashCode() + y.hashCode()
+}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/math/Vector2d.kt b/src/commonMain/kotlin/com/dropbear/math/Vector2d.kt
new file mode 100644
index 0000000..d1d9e10
--- /dev/null
+++ b/src/commonMain/kotlin/com/dropbear/math/Vector2d.kt
@@ -0,0 +1,62 @@
+package com.dropbear.math
+
+import kotlin.math.sqrt
+import kotlin.jvm.JvmField
+import kotlin.jvm.JvmStatic
+
+/**
+ * A class for holding a vector of `2` double values.
+ */
+class Vector2d(
+    @JvmField var x: Double,
+    @JvmField var y: Double
+) {
+    companion object {
+        @JvmStatic fun zero() = Vector2d(0.0, 0.0)
+        @JvmStatic fun one() = Vector2d(1.0, 1.0)
+    }
+
+    operator fun plus(other: Vector2d) = Vector2d(x + other.x, y + other.y)
+    operator fun plus(scalar: Double) = Vector2d(x + scalar, y + scalar)
+
+    operator fun minus(other: Vector2d) = Vector2d(x - other.x, y - other.y)
+    operator fun minus(scalar: Double) = Vector2d(x - scalar, y - scalar)
+
+    operator fun times(other: Vector2d) = Vector2d(x * other.x, y * other.y)
+    operator fun times(scalar: Double) = Vector2d(x * scalar, y * scalar)
+
+    operator fun div(other: Vector2d) = Vector2d(x / other.x, y / other.y)
+    operator fun div(scalar: Double) = Vector2d(x / scalar, y / scalar)
+
+    operator fun unaryMinus() = Vector2d(-x, -y)
+
+    fun length() = sqrt(x * x + y * y)
+    fun lengthSquared() = x * x + y * y
+
+    fun dot(other: Vector2d) = x * other.x + y * other.y
+
+    fun distanceTo(other: Vector2d): Double {
+        val dx = x - other.x
+        val dy = y - other.y
+        return sqrt(dx * dx + dy * dy)
+    }
+
+    fun normalize(): Vector2d {
+        val l = length()
+        return if (l != 0.0) this / l else zero()
+    }
+
+    fun lerp(target: Vector2d, alpha: Double): Vector2d {
+        val inv = 1.0 - alpha
+        return Vector2d(x * inv + target.x * alpha, y * inv + target.y * alpha)
+    }
+
+    fun toFloat() = Vector2f(x.toFloat(), y.toFloat())
+    fun toInt() = Vector2i(x.toInt(), y.toInt())
+
+    fun toGeneric() = Vector2(x, y)
+
+    override fun toString() = "Vector2d($x, $y)"
+    override fun equals(other: Any?) = other is Vector2d && x == other.x && y == other.y
+    override fun hashCode() = 31 * x.hashCode() + y.hashCode()
+}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/math/Vector2f.kt b/src/commonMain/kotlin/com/dropbear/math/Vector2f.kt
new file mode 100644
index 0000000..a203865
--- /dev/null
+++ b/src/commonMain/kotlin/com/dropbear/math/Vector2f.kt
@@ -0,0 +1,46 @@
+package com.dropbear.math
+
+import kotlin.math.sqrt
+import kotlin.jvm.JvmField
+import kotlin.jvm.JvmStatic
+
+/**
+ * A class for holding a vector of `2` float values.
+ */
+class Vector2f(
+    @JvmField var x: Float,
+    @JvmField var y: Float
+) {
+    companion object {
+        @JvmStatic
+        fun zero() = Vector2f(0f, 0f)
+    }
+
+    operator fun plus(other: Vector2f) = Vector2f(x + other.x, y + other.y)
+    operator fun plus(scalar: Float) = Vector2f(x + scalar, y + scalar)
+
+    operator fun minus(other: Vector2f) = Vector2f(x - other.x, y - other.y)
+    operator fun minus(scalar: Float) = Vector2f(x - scalar, y - scalar)
+
+    operator fun times(other: Vector2f) = Vector2f(x * other.x, y * other.y)
+    operator fun times(scalar: Float) = Vector2f(x * scalar, y * scalar)
+
+    operator fun div(other: Vector2f) = Vector2f(x / other.x, y / other.y)
+    operator fun div(scalar: Float) = Vector2f(x / scalar, y / scalar)
+
+    operator fun unaryMinus() = Vector2f(-x, -y)
+
+    fun length(): Float = sqrt(x * x + y * y)
+    fun lengthSquared(): Float = x * x + y * y
+
+    fun normalize(): Vector2f {
+        val l = length()
+        return if (l != 0f) Vector2f(x / l, y / l) else zero()
+    }
+
+    // --- Conversions ---
+    fun toDouble() = Vector2d(x.toDouble(), y.toDouble())
+    fun toInt() = Vector2i(x.toInt(), y.toInt())
+
+    override fun toString() = "Vector2f($x, $y)"
+}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/math/Vector2i.kt b/src/commonMain/kotlin/com/dropbear/math/Vector2i.kt
new file mode 100644
index 0000000..0b8e9db
--- /dev/null
+++ b/src/commonMain/kotlin/com/dropbear/math/Vector2i.kt
@@ -0,0 +1,32 @@
+package com.dropbear.math
+
+import kotlin.math.sqrt
+import kotlin.jvm.JvmField
+import kotlin.jvm.JvmStatic
+
+/**
+ * A class for holding a vector of `2` integer values.
+ */
+class Vector2i(
+    @JvmField var x: Int,
+    @JvmField var y: Int
+) {
+    companion object {
+        @JvmStatic
+        fun zero() = Vector2i(0, 0)
+    }
+
+    operator fun plus(other: Vector2i) = Vector2i(x + other.x, y + other.y)
+    operator fun minus(other: Vector2i) = Vector2i(x - other.x, y - other.y)
+
+    operator fun times(scalar: Int) = Vector2i(x * scalar, y * scalar)
+
+    operator fun div(scalar: Int) = Vector2i(x / scalar, y / scalar)
+
+    fun length(): Double = sqrt((x * x + y * y).toDouble())
+
+    fun toFloat() = Vector2f(x.toFloat(), y.toFloat())
+    fun toDouble() = Vector2d(x.toDouble(), y.toDouble())
+
+    override fun toString() = "Vector2i($x, $y)"
+}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/math/Vector3.kt b/src/commonMain/kotlin/com/dropbear/math/Vector3.kt
index 5c50af3..706e75d 100644
--- a/src/commonMain/kotlin/com/dropbear/math/Vector3.kt
+++ b/src/commonMain/kotlin/com/dropbear/math/Vector3.kt
@@ -1,227 +1,41 @@
 package com.dropbear.math
 
 import kotlin.jvm.JvmField
-import kotlin.math.sqrt
+import kotlin.jvm.JvmStatic
 
 /**
- * A class for holding a vector of `3` values of the same type.
+ * A Generic Vector3.
+ * WARNING: Uses boxing. Prefer [Vector3d]/[Vector3f]/[Vector3i] for performance.
  */
-class Vector3<T: Number>(
+class Vector3<T : Number>(
     @JvmField var x: T,
     @JvmField var y: T,
-    @JvmField var z: T,
-) : Vector<T, Vector3<T>>() {
+    @JvmField var z: T
+) {
     companion object {
-        /**
-         * Creates a new [com.dropbear.math.Vector3] of type `T` with one value.
-         */
-        fun <T: Number> uniform(value: T): Vector3<T> {
-            return Vector3(value, value, value)
-        }
+        @JvmStatic
+        fun fromDoubles(x: Double, y: Double, z: Double): Vector3<Double> = Vector3(x, y, z)
 
-        /**
-         * Creates a [com.dropbear.math.Vector3] of type [Double] filled with only zeroes
-         */
-        fun zero(): Vector3<Double> {
-            return Vector3(0.0, 0.0, 0.0)
-        }
-
-        fun x(): Vector3D {
-            return Vector3D(1.0, 0.0, 0.0)
-        }
-
-        fun y(): Vector3D {
-            return Vector3D(0.0, 1.0, 0.0)
-        }
-
-        fun z(): Vector3D {
-            return Vector3D(0.0, 0.0, 1.0)
-        }
-    }
-
-    /**
-     * Returns the [Vector3] to a [Vector3D] (Vector3 of type `Double`)
-     */
-    fun asDoubleVector(): Vector3<Double> {
-        return Vector3(this.x.toDouble(), this.y.toDouble(), this.z.toDouble())
-    }
-
-    override fun normalize(): Vector3<T> {
-        val length = length()
-        if (length > 0.0) {
-            val invLength = 1.0 / length
-            @Suppress("UNCHECKED_CAST")
-            x = (x.toDouble() * invLength) as T
-            @Suppress("UNCHECKED_CAST")
-            y = (y.toDouble() * invLength) as T
-            @Suppress("UNCHECKED_CAST")
-            z = (z.toDouble() * invLength) as T
-        }
-        return this
-    }
-
-    override operator fun plus(other: Vector3<T>): Vector3<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector3(
-            x.toDouble() + other.x.toDouble(),
-            y.toDouble() + other.y.toDouble(),
-            z.toDouble() + other.z.toDouble()
-        ) as Vector3<T>
-    }
-
-    override operator fun plus(scalar: T): Vector3<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector3(
-            x.toDouble() + scalar.toDouble(),
-            y.toDouble() + scalar.toDouble(),
-            z.toDouble() + scalar.toDouble()
-        ) as Vector3<T>
+        @JvmStatic
+        fun zero(): Vector3<Double> = Vector3(0.0, 0.0, 0.0)
     }
 
-    override operator fun minus(other: Vector3<T>): Vector3<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector3(
-            x.toDouble() - other.x.toDouble(),
-            y.toDouble() - other.y.toDouble(),
-            z.toDouble() - other.z.toDouble()
-        ) as Vector3<T>
-    }
-
-    override operator fun minus(scalar: T): Vector3<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector3(
-            x.toDouble() - scalar.toDouble(),
-            y.toDouble() - scalar.toDouble(),
-            z.toDouble() - scalar.toDouble()
-        ) as Vector3<T>
-    }
+    fun asVector3d(): Vector3d = Vector3d(x.toDouble(), y.toDouble(), z.toDouble())
+    fun asVector3f(): Vector3f = Vector3f(x.toFloat(), y.toFloat(), z.toFloat())
+    fun asVector3i(): Vector3i = Vector3i(x.toInt(), y.toInt(), z.toInt())
 
-    override operator fun times(other: Vector3<T>): Vector3<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector3(
-            x.toDouble() * other.x.toDouble(),
-            y.toDouble() * other.y.toDouble(),
-            z.toDouble() * other.z.toDouble()
-        ) as Vector3<T>
-    }
-
-    override operator fun times(scalar: T): Vector3<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector3(
-            x.toDouble() * scalar.toDouble(),
-            y.toDouble() * scalar.toDouble(),
-            z.toDouble() * scalar.toDouble()
-        ) as Vector3<T>
-    }
+    override fun toString() = "Vector3($x, $y, $z)"
 
-    override operator fun div(other: Vector3<T>): Vector3<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector3(
-            x.toDouble() / other.x.toDouble(),
-            y.toDouble() / other.y.toDouble(),
-            z.toDouble() / other.z.toDouble()
-        ) as Vector3<T>
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is Vector3<*>) return false
+        return x == other.x && y == other.y && z == other.z
     }
 
-    override operator fun div(scalar: T): Vector3<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector3(
-            x.toDouble() / scalar.toDouble(),
-            y.toDouble() / scalar.toDouble(),
-            z.toDouble() / scalar.toDouble()
-        ) as Vector3<T>
+    override fun hashCode(): Int {
+        var result = x.hashCode()
+        result = 31 * result + y.hashCode()
+        result = 31 * result + z.hashCode()
+        return result
     }
-
-    fun lengthSquared(): Double {
-        val dx = x.toDouble()
-        val dy = y.toDouble()
-        val dz = z.toDouble()
-        return dx * dx + dy * dy + dz * dz
-    }
-
-    fun dot(other: Vector3<T>): Double {
-        return x.toDouble() * other.x.toDouble() +
-                y.toDouble() * other.y.toDouble() +
-                z.toDouble() * other.z.toDouble()
-    }
-
-    fun cross(other: Vector3<T>): Vector3<Double> {
-        val ax = x.toDouble()
-        val ay = y.toDouble()
-        val az = z.toDouble()
-        val bx = other.x.toDouble()
-        val by = other.y.toDouble()
-        val bz = other.z.toDouble()
-        return Vector3(
-            ay * bz - az * by,
-            az * bx - ax * bz,
-            ax * by - ay * bx
-        )
-    }
-
-    fun distanceTo(other: Vector3<T>): Double {
-        val dx = x.toDouble() - other.x.toDouble()
-        val dy = y.toDouble() - other.y.toDouble()
-        val dz = z.toDouble() - other.z.toDouble()
-        return sqrt(dx * dx + dy * dy + dz * dz)
-    }
-
-    fun normalizedCopy(): Vector3<Double> {
-        val length = length()
-        if (length == 0.0) {
-            return zero()
-        }
-        val invLength = 1.0 / length
-        return Vector3(
-            x.toDouble() * invLength,
-            y.toDouble() * invLength,
-            z.toDouble() * invLength
-        )
-    }
-
-    fun lerp(target: Vector3<T>, alpha: Double): Vector3<Double> {
-        val inverse = 1.0 - alpha
-        return Vector3(
-            x.toDouble() * inverse + target.x.toDouble() * alpha,
-            y.toDouble() * inverse + target.y.toDouble() * alpha,
-            z.toDouble() * inverse + target.z.toDouble() * alpha
-        )
-    }
-
-    operator fun unaryMinus(): Vector3<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector3(-x.toDouble(), -y.toDouble(), -z.toDouble()) as Vector3<T>
-    }
-
-    fun toVector2(): Vector2<T> {
-        return Vector2(x, y)
-    }
-
-    fun toVector4(w: T): Vector4<T> {
-        return Vector4(x, y, z, w)
-    }
-
-    operator fun component1(): T = x
-    operator fun component2(): T = y
-    operator fun component3(): T = z
-
-    /**
-     * Returns the magnitude/length of the vector
-     *
-     * ## Math
-     * `sqrt(x^2 + y^2 + z^2)`
-     */
-    override fun length(): Double {
-        return sqrt(x.toDouble() * x.toDouble() + y.toDouble() * y.toDouble() + z.toDouble() * z.toDouble())
-    }
-
-    override fun copy(): Vector3<T> {
-        return Vector3(x, y, z)
-    }
-
-    override fun toString(): String {
-        return "Vector3(x=$x, y=$y, z=$z)"
-    }
-}
-
-typealias Vector3D = Vector3<Double>
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/math/Vector3d.kt b/src/commonMain/kotlin/com/dropbear/math/Vector3d.kt
new file mode 100644
index 0000000..7f300c1
--- /dev/null
+++ b/src/commonMain/kotlin/com/dropbear/math/Vector3d.kt
@@ -0,0 +1,87 @@
+package com.dropbear.math
+
+import kotlin.math.sqrt
+import kotlin.jvm.JvmField
+import kotlin.jvm.JvmStatic
+
+class Vector3d(
+    @JvmField var x: Double,
+    @JvmField var y: Double,
+    @JvmField var z: Double
+) {
+    companion object {
+        @JvmStatic fun zero() = Vector3d(0.0, 0.0, 0.0)
+        @JvmStatic fun one() = Vector3d(1.0, 1.0, 1.0)
+
+        @JvmStatic fun right() = Vector3d(1.0, 0.0, 0.0) // X
+        @JvmStatic fun up()    = Vector3d(0.0, 1.0, 0.0) // Y
+        @JvmStatic fun forward() = Vector3d(0.0, 0.0, 1.0) // Z
+    }
+
+    operator fun plus(other: Vector3d) = Vector3d(x + other.x, y + other.y, z + other.z)
+    operator fun plus(scalar: Double) = Vector3d(x + scalar, y + scalar, z + scalar)
+
+    operator fun minus(other: Vector3d) = Vector3d(x - other.x, y - other.y, z - other.z)
+    operator fun minus(scalar: Double) = Vector3d(x - scalar, y - scalar, z - scalar)
+
+    operator fun times(other: Vector3d) = Vector3d(x * other.x, y * other.y, z * other.z)
+    operator fun times(scalar: Double) = Vector3d(x * scalar, y * scalar, z * scalar)
+
+    operator fun div(other: Vector3d) = Vector3d(x / other.x, y / other.y, z / other.z)
+    operator fun div(scalar: Double) = Vector3d(x / scalar, y / scalar, z / scalar)
+
+    operator fun unaryMinus() = Vector3d(-x, -y, -z)
+
+    fun length() = sqrt(x * x + y * y + z * z)
+    fun lengthSquared() = x * x + y * y + z * z
+
+    fun dot(other: Vector3d) = x * other.x + y * other.y + z * other.z
+
+    /**
+     * Calculates the Cross Product.
+     * Result is perpendicular to both this vector and the other.
+     */
+    fun cross(other: Vector3d): Vector3d {
+        return Vector3d(
+            y * other.z - z * other.y,
+            z * other.x - x * other.z,
+            x * other.y - y * other.x
+        )
+    }
+
+    fun distanceTo(other: Vector3d): Double {
+        val dx = x - other.x
+        val dy = y - other.y
+        val dz = z - other.z
+        return sqrt(dx * dx + dy * dy + dz * dz)
+    }
+
+    fun normalize(): Vector3d {
+        val l = length()
+        return if (l != 0.0) this / l else zero()
+    }
+
+    fun lerp(target: Vector3d, alpha: Double): Vector3d {
+        val inv = 1.0 - alpha
+        return Vector3d(
+            x * inv + target.x * alpha,
+            y * inv + target.y * alpha,
+            z * inv + target.z * alpha
+        )
+    }
+
+    fun toFloat() = Vector3f(x.toFloat(), y.toFloat(), z.toFloat())
+    fun toInt() = Vector3i(x.toInt(), y.toInt(), z.toInt())
+    fun toVector2d() = Vector2d(x, y)
+
+    fun toGeneric() = Vector3(x, y, z)
+
+    override fun toString() = "Vector3d($x, $y, $z)"
+    override fun equals(other: Any?) = other is Vector3d && x == other.x && y == other.y && z == other.z
+    override fun hashCode(): Int {
+        var result = x.hashCode()
+        result = 31 * result + y.hashCode()
+        result = 31 * result + z.hashCode()
+        return result
+    }
+}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/math/Vector3f.kt b/src/commonMain/kotlin/com/dropbear/math/Vector3f.kt
new file mode 100644
index 0000000..ed5ad2b
--- /dev/null
+++ b/src/commonMain/kotlin/com/dropbear/math/Vector3f.kt
@@ -0,0 +1,54 @@
+package com.dropbear.math
+
+import kotlin.math.sqrt
+import kotlin.jvm.JvmField
+import kotlin.jvm.JvmStatic
+
+class Vector3f(
+    @JvmField var x: Float,
+    @JvmField var y: Float,
+    @JvmField var z: Float
+) {
+    companion object {
+        @JvmStatic
+        fun zero() = Vector3f(0f, 0f, 0f)
+    }
+
+    operator fun plus(other: Vector3f) = Vector3f(x + other.x, y + other.y, z + other.z)
+    operator fun plus(scalar: Float) = Vector3f(x + scalar, y + scalar, z + scalar)
+
+    operator fun minus(other: Vector3f) = Vector3f(x - other.x, y - other.y, z - other.z)
+    operator fun minus(scalar: Float) = Vector3f(x - scalar, y - scalar, z - scalar)
+
+    operator fun times(other: Vector3f) = Vector3f(x * other.x, y * other.y, z * other.z)
+    operator fun times(scalar: Float) = Vector3f(x * scalar, y * scalar, z * scalar)
+
+    operator fun div(other: Vector3f) = Vector3f(x / other.x, y / other.y, z / other.z)
+    operator fun div(scalar: Float) = Vector3f(x / scalar, y / scalar, z / scalar)
+
+    operator fun unaryMinus() = Vector3f(-x, -y, -z)
+
+    fun length(): Float = sqrt(x * x + y * y + z * z)
+    fun lengthSquared(): Float = x * x + y * y + z * z
+
+    fun dot(other: Vector3f) = x * other.x + y * other.y + z * other.z
+
+    fun cross(other: Vector3f): Vector3f {
+        return Vector3f(
+            y * other.z - z * other.y,
+            z * other.x - x * other.z,
+            x * other.y - y * other.x
+        )
+    }
+
+    fun normalize(): Vector3f {
+        val l = length()
+        return if (l != 0f) Vector3f(x / l, y / l, z / l) else zero()
+    }
+
+    fun toDouble() = Vector3d(x.toDouble(), y.toDouble(), z.toDouble())
+    fun toInt() = Vector3i(x.toInt(), y.toInt(), z.toInt())
+    fun toVector2f() = Vector2f(x, y)
+
+    override fun toString() = "Vector3f($x, $y, $z)"
+}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/math/Vector3i.kt b/src/commonMain/kotlin/com/dropbear/math/Vector3i.kt
new file mode 100644
index 0000000..2e4a7a0
--- /dev/null
+++ b/src/commonMain/kotlin/com/dropbear/math/Vector3i.kt
@@ -0,0 +1,28 @@
+package com.dropbear.math
+
+import kotlin.math.sqrt
+import kotlin.jvm.JvmField
+import kotlin.jvm.JvmStatic
+
+class Vector3i(
+    @JvmField var x: Int,
+    @JvmField var y: Int,
+    @JvmField var z: Int
+) {
+    companion object {
+        @JvmStatic
+        fun zero() = Vector3i(0, 0, 0)
+    }
+
+    operator fun plus(other: Vector3i) = Vector3i(x + other.x, y + other.y, z + other.z)
+    operator fun minus(other: Vector3i) = Vector3i(x - other.x, y - other.y, z - other.z)
+    operator fun times(scalar: Int) = Vector3i(x * scalar, y * scalar, z * scalar)
+    operator fun div(scalar: Int) = Vector3i(x / scalar, y / scalar, z / scalar)
+
+    fun length(): Double = sqrt((x * x + y * y + z * z).toDouble())
+
+    fun toFloat() = Vector3f(x.toFloat(), y.toFloat(), z.toFloat())
+    fun toDouble() = Vector3d(x.toDouble(), y.toDouble(), z.toDouble())
+
+    override fun toString() = "Vector3i($x, $y, $z)"
+}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/math/Vector4.kt b/src/commonMain/kotlin/com/dropbear/math/Vector4.kt
index 408a483..c5ac7d1 100644
--- a/src/commonMain/kotlin/com/dropbear/math/Vector4.kt
+++ b/src/commonMain/kotlin/com/dropbear/math/Vector4.kt
@@ -1,228 +1,48 @@
 package com.dropbear.math
 
 import kotlin.jvm.JvmField
-import kotlin.math.sqrt
+import kotlin.jvm.JvmStatic
 
 /**
- * A class for holding a vector of `4` values of the same type.
+ * A Generic Vector4.
+ * WARNING: Uses boxing. Prefer [Vector4d]/[Vector4f]/[Vector4i] for performance.
  */
-class Vector4<T: Number>(
+class Vector4<T : Number>(
     @JvmField var x: T,
     @JvmField var y: T,
     @JvmField var z: T,
-    @JvmField var w: T,
-) : Vector<T, Vector4<T>>() {
+    @JvmField var w: T
+) {
     companion object {
-        /**
-         * Creates a new [com.dropbear.math.Vector4] of type `T` with one value.
-         */
-        fun <T: Number> uniform(value: T): Vector4<T> {
-            return Vector4(value, value, value, value)
-        }
+        @JvmStatic
+        fun fromDoubles(x: Double, y: Double, z: Double, w: Double): Vector4<Double> = Vector4(x, y, z, w)
 
-        /**
-         * Creates a [com.dropbear.math.Vector4] of type [Double] filled with only zeroes
-         */
-        fun zero(): Vector4<Double> {
-            return Vector4(0.0, 0.0, 0.0, 0.0)
-        }
-
-        fun x(): Vector4D {
-            return Vector4D(1.0, 0.0, 0.0, 0.0)
-        }
-
-        fun y(): Vector4D {
-            return Vector4D(0.0, 1.0, 0.0, 0.0)
-        }
-
-        fun z(): Vector4D {
-            return Vector4D(0.0, 0.0, 1.0, 0.0)
-        }
-
-        fun w(): Vector4D {
-            return Vector4D(0.0, 0.0, 0.0, 1.0)
-        }
-    }
-
-    fun asDoubleVector(): Vector4<Double> {
-        return Vector4(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble())
-    }
-
-    override fun normalize(): Vector4<T> {
-        val length = length()
-        if (length > 0.0) {
-            val invLength = 1.0 / length
-            @Suppress("UNCHECKED_CAST")
-            x = (x.toDouble() * invLength) as T
-            @Suppress("UNCHECKED_CAST")
-            y = (y.toDouble() * invLength) as T
-            @Suppress("UNCHECKED_CAST")
-            z = (z.toDouble() * invLength) as T
-            @Suppress("UNCHECKED_CAST")
-            w = (w.toDouble() * invLength) as T
-        }
-        return this
-    }
-
-    override operator fun plus(other: Vector4<T>): Vector4<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector4(
-            x.toDouble() + other.x.toDouble(),
-            y.toDouble() + other.y.toDouble(),
-            z.toDouble() + other.z.toDouble(),
-            w.toDouble() + other.w.toDouble()
-        ) as Vector4<T>
+        @JvmStatic
+        fun zero(): Vector4<Double> = Vector4(0.0, 0.0, 0.0, 0.0)
     }
 
-    override operator fun plus(scalar: T): Vector4<T> {
-        val value = scalar.toDouble()
-        @Suppress("UNCHECKED_CAST")
-        return Vector4(
-            x.toDouble() + value,
-            y.toDouble() + value,
-            z.toDouble() + value,
-            w.toDouble() + value
-        ) as Vector4<T>
-    }
-
-    override operator fun minus(other: Vector4<T>): Vector4<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector4(
-            x.toDouble() - other.x.toDouble(),
-            y.toDouble() - other.y.toDouble(),
-            z.toDouble() - other.z.toDouble(),
-            w.toDouble() - other.w.toDouble()
-        ) as Vector4<T>
-    }
-
-    override operator fun minus(scalar: T): Vector4<T> {
-        val value = scalar.toDouble()
-        @Suppress("UNCHECKED_CAST")
-        return Vector4(
-            x.toDouble() - value,
-            y.toDouble() - value,
-            z.toDouble() - value,
-            w.toDouble() - value
-        ) as Vector4<T>
-    }
+    fun asVector4d(): Vector4d = Vector4d(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble())
+    fun asVector4f(): Vector4f = Vector4f(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat())
+    fun asVector4i(): Vector4i = Vector4i(x.toInt(), y.toInt(), z.toInt(), w.toInt())
 
-    override operator fun times(other: Vector4<T>): Vector4<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector4(
-            x.toDouble() * other.x.toDouble(),
-            y.toDouble() * other.y.toDouble(),
-            z.toDouble() * other.z.toDouble(),
-            w.toDouble() * other.w.toDouble()
-        ) as Vector4<T>
-    }
+    operator fun component1() = x
+    operator fun component2() = y
+    operator fun component3() = z
+    operator fun component4() = w
 
-    override operator fun times(scalar: T): Vector4<T> {
-        val value = scalar.toDouble()
-        @Suppress("UNCHECKED_CAST")
-        return Vector4(
-            x.toDouble() * value,
-            y.toDouble() * value,
-            z.toDouble() * value,
-            w.toDouble() * value
-        ) as Vector4<T>
-    }
+    override fun toString() = "Vector4($x, $y, $z, $w)"
 
-    override operator fun div(other: Vector4<T>): Vector4<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector4(
-            x.toDouble() / other.x.toDouble(),
-            y.toDouble() / other.y.toDouble(),
-            z.toDouble() / other.z.toDouble(),
-            w.toDouble() / other.w.toDouble()
-        ) as Vector4<T>
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is Vector4<*>) return false
+        return x == other.x && y == other.y && z == other.z && w == other.w
     }
 
-    override operator fun div(scalar: T): Vector4<T> {
-        val value = scalar.toDouble()
-        @Suppress("UNCHECKED_CAST")
-        return Vector4(
-            x.toDouble() / value,
-            y.toDouble() / value,
-            z.toDouble() / value,
-            w.toDouble() / value
-        ) as Vector4<T>
+    override fun hashCode(): Int {
+        var result = x.hashCode()
+        result = 31 * result + y.hashCode()
+        result = 31 * result + z.hashCode()
+        result = 31 * result + w.hashCode()
+        return result
     }
-
-    fun lengthSquared(): Double {
-        val dx = x.toDouble()
-        val dy = y.toDouble()
-        val dz = z.toDouble()
-        val dw = w.toDouble()
-        return dx * dx + dy * dy + dz * dz + dw * dw
-    }
-
-    fun dot(other: Vector4<T>): Double {
-        return x.toDouble() * other.x.toDouble() +
-                y.toDouble() * other.y.toDouble() +
-                z.toDouble() * other.z.toDouble() +
-                w.toDouble() * other.w.toDouble()
-    }
-
-    fun distanceTo(other: Vector4<T>): Double {
-        val dx = x.toDouble() - other.x.toDouble()
-        val dy = y.toDouble() - other.y.toDouble()
-        val dz = z.toDouble() - other.z.toDouble()
-        val dw = w.toDouble() - other.w.toDouble()
-        return sqrt(dx * dx + dy * dy + dz * dz + dw * dw)
-    }
-
-    fun normalizedCopy(): Vector4<Double> {
-        val length = length()
-        if (length == 0.0) {
-            return zero()
-        }
-        val invLength = 1.0 / length
-        return Vector4(
-            x.toDouble() * invLength,
-            y.toDouble() * invLength,
-            z.toDouble() * invLength,
-            w.toDouble() * invLength
-        )
-    }
-
-    fun lerp(target: Vector4<T>, alpha: Double): Vector4<Double> {
-        val inverse = 1.0 - alpha
-        return Vector4(
-            x.toDouble() * inverse + target.x.toDouble() * alpha,
-            y.toDouble() * inverse + target.y.toDouble() * alpha,
-            z.toDouble() * inverse + target.z.toDouble() * alpha,
-            w.toDouble() * inverse + target.w.toDouble() * alpha
-        )
-    }
-
-    operator fun unaryMinus(): Vector4<T> {
-        @Suppress("UNCHECKED_CAST")
-        return Vector4(-x.toDouble(), -y.toDouble(), -z.toDouble(), -w.toDouble()) as Vector4<T>
-    }
-
-    fun toVector3(): Vector3<T> {
-        return Vector3(x, y, z)
-    }
-
-    operator fun component1(): T = x
-    operator fun component2(): T = y
-    operator fun component3(): T = z
-    operator fun component4(): T = w
-
-    /**
-     * Returns the magnitude/length of the vector
-     */
-    override fun length(): Double {
-        return sqrt(lengthSquared())
-    }
-
-    override fun copy(): Vector4<T> {
-        return Vector4(x, y, z, w)
-    }
-
-    override fun toString(): String {
-        return "Vector4(x=$x, y=$y, z=$z, w=$w)"
-    }
-}
-
-typealias Vector4D = Vector4<Double>
+}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/math/Vector4d.kt b/src/commonMain/kotlin/com/dropbear/math/Vector4d.kt
new file mode 100644
index 0000000..50b695b
--- /dev/null
+++ b/src/commonMain/kotlin/com/dropbear/math/Vector4d.kt
@@ -0,0 +1,81 @@
+package com.dropbear.math
+
+import kotlin.math.sqrt
+import kotlin.jvm.JvmField
+import kotlin.jvm.JvmStatic
+
+class Vector4d(
+    @JvmField var x: Double,
+    @JvmField var y: Double,
+    @JvmField var z: Double,
+    @JvmField var w: Double
+) {
+    companion object {
+        @JvmStatic fun zero() = Vector4d(0.0, 0.0, 0.0, 0.0)
+        @JvmStatic fun one() = Vector4d(1.0, 1.0, 1.0, 1.0)
+    }
+
+    operator fun plus(other: Vector4d) = Vector4d(x + other.x, y + other.y, z + other.z, w + other.w)
+    operator fun plus(scalar: Double) = Vector4d(x + scalar, y + scalar, z + scalar, w + scalar)
+
+    operator fun minus(other: Vector4d) = Vector4d(x - other.x, y - other.y, z - other.z, w - other.w)
+    operator fun minus(scalar: Double) = Vector4d(x - scalar, y - scalar, z - scalar, w - scalar)
+
+    operator fun times(other: Vector4d) = Vector4d(x * other.x, y * other.y, z * other.z, w * other.w)
+    operator fun times(scalar: Double) = Vector4d(x * scalar, y * scalar, z * scalar, w * scalar)
+
+    operator fun div(other: Vector4d) = Vector4d(x / other.x, y / other.y, z / other.z, w / other.w)
+    operator fun div(scalar: Double) = Vector4d(x / scalar, y / scalar, z / scalar, w / scalar)
+
+    operator fun unaryMinus() = Vector4d(-x, -y, -z, -w)
+
+    fun length() = sqrt(x * x + y * y + z * z + w * w)
+    fun lengthSquared() = x * x + y * y + z * z + w * w
+
+    fun dot(other: Vector4d) = x * other.x + y * other.y + z * other.z + w * other.w
+
+    fun distanceTo(other: Vector4d): Double {
+        val dx = x - other.x
+        val dy = y - other.y
+        val dz = z - other.z
+        val dw = w - other.w
+        return sqrt(dx * dx + dy * dy + dz * dz + dw * dw)
+    }
+
+    fun normalize(): Vector4d {
+        val l = length()
+        return if (l != 0.0) this / l else zero()
+    }
+
+    fun lerp(target: Vector4d, alpha: Double): Vector4d {
+        val inv = 1.0 - alpha
+        return Vector4d(
+            x * inv + target.x * alpha,
+            y * inv + target.y * alpha,
+            z * inv + target.z * alpha,
+            w * inv + target.w * alpha
+        )
+    }
+
+    fun toFloat() = Vector4f(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat())
+    fun toInt() = Vector4i(x.toInt(), y.toInt(), z.toInt(), w.toInt())
+    fun toVector3d() = Vector3d(x, y, z)
+    fun toVector2d() = Vector2d(x, y)
+
+    operator fun component1() = x
+    operator fun component2() = y
+    operator fun component3() = z
+    operator fun component4() = w
+
+    fun toGeneric() = Vector4(x, y, z, w)
+
+    override fun toString() = "Vector4d($x, $y, $z, $w)"
+    override fun equals(other: Any?) = other is Vector4d && x == other.x && y == other.y && z == other.z && w == other.w
+    override fun hashCode(): Int {
+        var result = x.hashCode()
+        result = 31 * result + y.hashCode()
+        result = 31 * result + z.hashCode()
+        result = 31 * result + w.hashCode()
+        return result
+    }
+}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/math/Vector4f.kt b/src/commonMain/kotlin/com/dropbear/math/Vector4f.kt
new file mode 100644
index 0000000..02d4978
--- /dev/null
+++ b/src/commonMain/kotlin/com/dropbear/math/Vector4f.kt
@@ -0,0 +1,52 @@
+package com.dropbear.math
+
+import kotlin.math.sqrt
+import kotlin.jvm.JvmField
+import kotlin.jvm.JvmStatic
+
+class Vector4f(
+    @JvmField var x: Float,
+    @JvmField var y: Float,
+    @JvmField var z: Float,
+    @JvmField var w: Float
+) {
+    companion object {
+        @JvmStatic
+        fun zero() = Vector4f(0f, 0f, 0f, 0f)
+    }
+
+    operator fun plus(other: Vector4f) = Vector4f(x + other.x, y + other.y, z + other.z, w + other.w)
+    operator fun plus(scalar: Float) = Vector4f(x + scalar, y + scalar, z + scalar, w + scalar)
+
+    operator fun minus(other: Vector4f) = Vector4f(x - other.x, y - other.y, z - other.z, w - other.w)
+    operator fun minus(scalar: Float) = Vector4f(x - scalar, y - scalar, z - scalar, w - scalar)
+
+    operator fun times(other: Vector4f) = Vector4f(x * other.x, y * other.y, z * other.z, w * other.w)
+    operator fun times(scalar: Float) = Vector4f(x * scalar, y * scalar, z * scalar, w * scalar)
+
+    operator fun div(other: Vector4f) = Vector4f(x / other.x, y / other.y, z / other.z, w / other.w)
+    operator fun div(scalar: Float) = Vector4f(x / scalar, y / scalar, z / scalar, w / scalar)
+
+    operator fun unaryMinus() = Vector4f(-x, -y, -z, -w)
+
+    fun length(): Float = sqrt(x * x + y * y + z * z + w * w)
+    fun lengthSquared(): Float = x * x + y * y + z * z + w * w
+
+    fun dot(other: Vector4f) = x * other.x + y * other.y + z * other.z + w * other.w
+
+    fun normalize(): Vector4f {
+        val l = length()
+        return if (l != 0f) Vector4f(x / l, y / l, z / l, w / l) else zero()
+    }
+
+    fun toDouble() = Vector4d(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble())
+    fun toInt() = Vector4i(x.toInt(), y.toInt(), z.toInt(), w.toInt())
+    fun toVector3f() = Vector3f(x, y, z)
+
+    operator fun component1() = x
+    operator fun component2() = y
+    operator fun component3() = z
+    operator fun component4() = w
+
+    override fun toString() = "Vector4f($x, $y, $z, $w)"
+}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/math/Vector4i.kt b/src/commonMain/kotlin/com/dropbear/math/Vector4i.kt
new file mode 100644
index 0000000..b3af7e5
--- /dev/null
+++ b/src/commonMain/kotlin/com/dropbear/math/Vector4i.kt
@@ -0,0 +1,35 @@
+package com.dropbear.math
+
+import kotlin.math.sqrt
+import kotlin.jvm.JvmField
+import kotlin.jvm.JvmStatic
+
+class Vector4i(
+    @JvmField var x: Int,
+    @JvmField var y: Int,
+    @JvmField var z: Int,
+    @JvmField var w: Int
+) {
+    companion object {
+        @JvmStatic
+        fun zero() = Vector4i(0, 0, 0, 0)
+    }
+
+    operator fun plus(other: Vector4i) = Vector4i(x + other.x, y + other.y, z + other.z, w + other.w)
+    operator fun minus(other: Vector4i) = Vector4i(x - other.x, y - other.y, z - other.z, w - other.w)
+
+    operator fun times(scalar: Int) = Vector4i(x * scalar, y * scalar, z * scalar, w * scalar)
+    operator fun div(scalar: Int) = Vector4i(x / scalar, y / scalar, z / scalar, w / scalar)
+
+    fun length(): Double = sqrt((x * x + y * y + z * z + w * w).toDouble())
+
+    fun toFloat() = Vector4f(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat())
+    fun toDouble() = Vector4d(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble())
+
+    operator fun component1() = x
+    operator fun component2() = y
+    operator fun component3() = z
+    operator fun component4() = w
+
+    override fun toString() = "Vector4i($x, $y, $z, $w)"
+}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/physics/Collider.kt b/src/commonMain/kotlin/com/dropbear/physics/Collider.kt
index 70c09b3..3b9d9e3 100644
--- a/src/commonMain/kotlin/com/dropbear/physics/Collider.kt
+++ b/src/commonMain/kotlin/com/dropbear/physics/Collider.kt
@@ -1,7 +1,7 @@
 package com.dropbear.physics
 
 import com.dropbear.EntityId
-import com.dropbear.math.Vector3D
+import com.dropbear.math.Vector3d
 
 class Collider(
     internal val index: Index,
@@ -23,10 +23,10 @@ class Collider(
     var isSensor: Boolean
         get() = getColliderIsSensor(this)
         set(value) = setColliderIsSensor(this, value)
-    var translation: Vector3D
+    var translation: Vector3d
         get() = getColliderTranslation(this)
         set(value) = setColliderTranslation(this, value)
-    var rotation: Vector3D
+    var rotation: Vector3d
         get() = getColliderRotation(this)
         set(value) = setColliderRotation(this, value)
     var mass: Double
@@ -44,9 +44,9 @@ expect fun Collider.getColliderRestitution(collider: Collider): Double
 expect fun Collider.setColliderRestitution(collider: Collider, restitution: Double)
 expect fun Collider.getColliderIsSensor(collider: Collider): Boolean
 expect fun Collider.setColliderIsSensor(collider: Collider, isSensor: Boolean)
-expect fun Collider.getColliderTranslation(collider: Collider): Vector3D
-expect fun Collider.setColliderTranslation(collider: Collider, translation: Vector3D)
-expect fun Collider.getColliderRotation(collider: Collider): Vector3D
-expect fun Collider.setColliderRotation(collider: Collider, rotation: Vector3D)
+expect fun Collider.getColliderTranslation(collider: Collider): Vector3d
+expect fun Collider.setColliderTranslation(collider: Collider, translation: Vector3d)
+expect fun Collider.getColliderRotation(collider: Collider): Vector3d
+expect fun Collider.setColliderRotation(collider: Collider, rotation: Vector3d)
 expect fun Collider.getColliderMass(collider: Collider): Double
 expect fun Collider.setColliderMass(collider: Collider, mass: Double)
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/physics/ColliderShape.kt b/src/commonMain/kotlin/com/dropbear/physics/ColliderShape.kt
index 7384658..c0241ab 100644
--- a/src/commonMain/kotlin/com/dropbear/physics/ColliderShape.kt
+++ b/src/commonMain/kotlin/com/dropbear/physics/ColliderShape.kt
@@ -1,13 +1,13 @@
 package com.dropbear.physics
 
-import com.dropbear.math.Vector3D
+import com.dropbear.math.Vector3d
 
 sealed class ColliderShape {
 
     /**
      * Box shape with half-extents (half-width, half-height, half-depth).
      */
-    data class Box(val halfExtents: Vector3D) : ColliderShape()
+    data class Box(val halfExtents: Vector3d) : ColliderShape()
 
     /**
      * Sphere shape with radius.
diff --git a/src/commonMain/kotlin/com/dropbear/physics/RigidBody.kt b/src/commonMain/kotlin/com/dropbear/physics/RigidBody.kt
index 2dfc72b..2662fed 100644
--- a/src/commonMain/kotlin/com/dropbear/physics/RigidBody.kt
+++ b/src/commonMain/kotlin/com/dropbear/physics/RigidBody.kt
@@ -3,7 +3,7 @@ package com.dropbear.physics
 import com.dropbear.ecs.Component
 import com.dropbear.EntityId
 import com.dropbear.ecs.ComponentType
-import com.dropbear.math.Vector3D
+import com.dropbear.math.Vector3d
 
 class RigidBody(
     internal val index: Index,
@@ -21,10 +21,10 @@ class RigidBody(
     var ccdEnabled: Boolean
         get() = getRigidbodyCcdEnabled(this)
         set(value) = setRigidbodyCcdEnabled(this, value)
-    var linearVelocity: Vector3D
+    var linearVelocity: Vector3d
         get() = getRigidbodyLinearVelocity(this)
         set(value) = setRigidbodyLinearVelocity(this, value)
-    var angularVelocity: Vector3D
+    var angularVelocity: Vector3d
         get() = getRigidbodyAngularVelocity(this)
         set(value) = setRigidbodyAngularVelocity(this, value)
     var linearDamping: Double
@@ -48,7 +48,7 @@ class RigidBody(
      *
      * Typically used for jumping or explosions.
      */
-    fun applyImpulse(impulse: Vector3D) {
+    fun applyImpulse(impulse: Vector3d) {
         applyImpulse(impulse.x, impulse.y, impulse.z)
     }
 
@@ -66,7 +66,7 @@ class RigidBody(
      *
      * Typically used for spinning objects.
      */
-    fun applyTorqueImpulse(impulse: Vector3D) {
+    fun applyTorqueImpulse(impulse: Vector3d) {
         applyTorqueImpulse(impulse.x, impulse.y, impulse.z)
     }
 
@@ -95,10 +95,10 @@ expect fun RigidBody.getRigidbodyCanSleep(rigidBody: RigidBody): Boolean
 expect fun RigidBody.setRigidbodyCanSleep(rigidBody: RigidBody, canSleep: Boolean)
 expect fun RigidBody.getRigidbodyCcdEnabled(rigidBody: RigidBody): Boolean
 expect fun RigidBody.setRigidbodyCcdEnabled(rigidBody: RigidBody, ccdEnabled: Boolean)
-expect fun RigidBody.getRigidbodyLinearVelocity(rigidBody: RigidBody): Vector3D
-expect fun RigidBody.setRigidbodyLinearVelocity(rigidBody: RigidBody, linearVelocity: Vector3D)
-expect fun RigidBody.getRigidbodyAngularVelocity(rigidBody: RigidBody): Vector3D
-expect fun RigidBody.setRigidbodyAngularVelocity(rigidBody: RigidBody, angularVelocity: Vector3D)
+expect fun RigidBody.getRigidbodyLinearVelocity(rigidBody: RigidBody): Vector3d
+expect fun RigidBody.setRigidbodyLinearVelocity(rigidBody: RigidBody, linearVelocity: Vector3d)
+expect fun RigidBody.getRigidbodyAngularVelocity(rigidBody: RigidBody): Vector3d
+expect fun RigidBody.setRigidbodyAngularVelocity(rigidBody: RigidBody, angularVelocity: Vector3d)
 expect fun RigidBody.getRigidbodyLinearDamping(rigidBody: RigidBody): Double
 expect fun RigidBody.setRigidbodyLinearDamping(rigidBody: RigidBody, linearDamping: Double)
 expect fun RigidBody.getRigidbodyAngularDamping(rigidBody: RigidBody): Double
diff --git a/src/commonMain/kotlin/com/dropbear/scene/SceneLoadHandle.kt b/src/commonMain/kotlin/com/dropbear/scene/SceneLoadHandle.kt
index 503b233..5c116fa 100644
--- a/src/commonMain/kotlin/com/dropbear/scene/SceneLoadHandle.kt
+++ b/src/commonMain/kotlin/com/dropbear/scene/SceneLoadHandle.kt
@@ -8,7 +8,9 @@ import com.dropbear.ffi.NativeEngine
 /**
  * A handle that allows you to check the state of an async scene load.
  */
-class SceneLoadHandle(val id: Long, val sceneName: String) {
+class SceneLoadHandle(val id: Long) {
+    val sceneName: String
+        get() = getSceneLoadHandleSceneName(id)
     /**
      * Switches the scene to the requested scene.
      *
@@ -63,6 +65,7 @@ class SceneLoadHandle(val id: Long, val sceneName: String) {
     }
 }
 
-expect fun SceneLoadHandle.switchToSceneAsync(): SceneLoadHandle
+expect fun SceneLoadHandle.getSceneLoadHandleSceneName(id: Long): String
+expect fun SceneLoadHandle.switchToSceneAsync()
 expect fun SceneLoadHandle.getSceneLoadProgress(): Progress
 expect fun SceneLoadHandle.getSceneLoadStatus(): SceneLoadStatus
\ No newline at end of file
diff --git a/src/commonMain/kotlin/com/dropbear/scene/SceneManager.kt b/src/commonMain/kotlin/com/dropbear/scene/SceneManager.kt
index 301e522..be993ce 100644
--- a/src/commonMain/kotlin/com/dropbear/scene/SceneManager.kt
+++ b/src/commonMain/kotlin/com/dropbear/scene/SceneManager.kt
@@ -35,15 +35,8 @@ class SceneManager() {
     fun switchToSceneImmediate(sceneName: String) {
         return switchToSceneImmediateNative(sceneName)
     }
-
-    /**
-     * Fetches the current scene that is currently being rendered.
-     */
-    fun getCurrentScene(): SceneMetadata {
-        TODO("Not implemented yet...")
-    }
 }
 
 expect fun SceneManager.loadSceneAsyncNative(sceneName: String): SceneLoadHandle?
-expect fun SceneManager.loadSceneAsyncNative(sceneName: String, loading_scene: String): SceneLoadHandle?
+expect fun SceneManager.loadSceneAsyncNative(sceneName: String, loadingScene: String): SceneLoadHandle?
 expect fun SceneManager.switchToSceneImmediateNative(sceneName: String)
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/Camera.jvm.kt b/src/jvmMain/kotlin/com/dropbear/Camera.jvm.kt
deleted file mode 100644
index ca85207..0000000
--- a/src/jvmMain/kotlin/com/dropbear/Camera.jvm.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.dropbear
-
-import com.dropbear.math.Vector3D
-
-actual fun Camera.getCameraEye(entity: EntityId): Vector3D {
-    TODO("Not yet implemented")
-}
-
-actual fun Camera.setCameraEye(entity: EntityId, value: Vector3D) {
-}
-
-actual fun Camera.getCameraTarget(entity: EntityId): Vector3D {
-    TODO("Not yet implemented")
-}
-
-actual fun Camera.setCameraTarget(entity: EntityId, value: Vector3D) {
-}
-
-actual fun Camera.getCameraUp(entity: EntityId): Vector3D {
-    TODO("Not yet implemented")
-}
-
-actual fun Camera.setCameraUp(entity: EntityId, value: Vector3D) {
-}
-
-actual fun Camera.getCameraAspect(entity: EntityId): Double {
-    TODO("Not yet implemented")
-}
-
-actual fun Camera.getCameraFovY(entity: EntityId): Double {
-    TODO("Not yet implemented")
-}
-
-actual fun Camera.setCameraFovY(entity: EntityId, value: Double) {
-}
-
-actual fun Camera.getCameraZNear(entity: EntityId): Double {
-    TODO("Not yet implemented")
-}
-
-actual fun Camera.setCameraZNear(entity: EntityId, value: Double) {
-}
-
-actual fun Camera.getCameraZFar(entity: EntityId): Double {
-    TODO("Not yet implemented")
-}
-
-actual fun Camera.setCameraZFar(entity: EntityId, value: Double) {
-}
-
-actual fun Camera.getCameraYaw(entity: EntityId): Double {
-    TODO("Not yet implemented")
-}
-
-actual fun Camera.setCameraYaw(entity: EntityId, value: Double) {
-}
-
-actual fun Camera.getCameraPitch(entity: EntityId): Double {
-    TODO("Not yet implemented")
-}
-
-actual fun Camera.setCameraPitch(entity: EntityId, value: Double) {
-}
-
-actual fun Camera.getCameraSpeed(entity: EntityId): Double {
-    TODO("Not yet implemented")
-}
-
-actual fun Camera.setCameraSpeed(entity: EntityId, value: Double) {
-}
-
-actual fun Camera.getCameraSensitivity(entity: EntityId): Double {
-    TODO("Not yet implemented")
-}
-
-actual fun Camera.setCameraSensitivity(entity: EntityId, value: Double) {
-}
-
-actual fun cameraExistsForEntity(entity: EntityId): Boolean {
-    TODO("Not yet implemented")
-}
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/CustomProperties.jvm.kt b/src/jvmMain/kotlin/com/dropbear/CustomProperties.jvm.kt
deleted file mode 100644
index 8923627..0000000
--- a/src/jvmMain/kotlin/com/dropbear/CustomProperties.jvm.kt
+++ /dev/null
@@ -1,93 +0,0 @@
-package com.dropbear
-
-actual fun CustomProperties.getStringProperty(
-    entityHandle: Long,
-    label: String
-): String? {
-    TODO("Not yet implemented")
-}
-
-actual fun CustomProperties.getIntProperty(entityHandle: Long, label: String): Int? {
-    TODO("Not yet implemented")
-}
-
-actual fun CustomProperties.getLongProperty(
-    entityHandle: Long,
-    label: String
-): Long? {
-    TODO("Not yet implemented")
-}
-
-actual fun CustomProperties.getDoubleProperty(
-    entityHandle: Long,
-    label: String
-): Double? {
-    TODO("Not yet implemented")
-}
-
-actual fun CustomProperties.getFloatProperty(
-    entityHandle: Long,
-    label: String
-): Float? {
-    TODO("Not yet implemented")
-}
-
-actual fun CustomProperties.getBoolProperty(
-    entityHandle: Long,
-    label: String
-): Boolean? {
-    TODO("Not yet implemented")
-}
-
-actual fun CustomProperties.getVec3Property(
-    entityHandle: Long,
-    label: String
-): FloatArray? {
-    TODO("Not yet implemented")
-}
-
-actual fun CustomProperties.setStringProperty(
-    entityHandle: Long,
-    label: String,
-    value: String
-) {
-}
-
-actual fun CustomProperties.setIntProperty(
-    entityHandle: Long,
-    label: String,
-    value: Int
-) {
-}
-
-actual fun CustomProperties.setLongProperty(
-    entityHandle: Long,
-    label: String,
-    value: Long
-) {
-}
-
-actual fun CustomProperties.setFloatProperty(
-    entityHandle: Long,
-    label: String,
-    value: Double
-) {
-}
-
-actual fun CustomProperties.setBoolProperty(
-    entityHandle: Long,
-    label: String,
-    value: Boolean
-) {
-}
-
-actual fun CustomProperties.setVec3Property(
-    entityHandle: Long,
-    label: String,
-    value: FloatArray
-) {
-}
-
-actual fun customPropertiesExistsForEntity(entityId: EntityId): Boolean {
-    TODO("Not yet implemented")
-}
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/DropbearEngine.jvm.kt b/src/jvmMain/kotlin/com/dropbear/DropbearEngine.jvm.kt
index ed78c58..53751cf 100644
--- a/src/jvmMain/kotlin/com/dropbear/DropbearEngine.jvm.kt
+++ b/src/jvmMain/kotlin/com/dropbear/DropbearEngine.jvm.kt
@@ -1,16 +1,15 @@
 package com.dropbear
 
-actual fun getEntity(label: String): Long? {
-    TODO("Not yet implemented")
-}
+import com.dropbear.components.Camera
 
-actual fun getCamera(label: String): Camera? {
-    TODO("Not yet implemented")
+actual fun getEntity(label: String): Long? {
+    return DropbearEngineNative.getEntity(DropbearEngine.native.worldHandle, label)
 }
 
 actual fun getAsset(eucaURI: String): Long? {
-    TODO("Not yet implemented")
+    return DropbearEngineNative.getAsset(DropbearEngine.native.worldHandle, eucaURI)
 }
 
 actual fun quit() {
+    DropbearEngineNative.quit(DropbearEngine.native.commandBufferHandle)
 }
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/DropbearEngineNative.java b/src/jvmMain/kotlin/com/dropbear/DropbearEngineNative.java
new file mode 100644
index 0000000..1501d04
--- /dev/null
+++ b/src/jvmMain/kotlin/com/dropbear/DropbearEngineNative.java
@@ -0,0 +1,11 @@
+package com.dropbear;
+
+public class DropbearEngineNative {
+    static {
+        new EucalyptusCoreLoader().ensureLoaded();
+    }
+
+    public static native Long getEntity(long worldPtr, String label);
+    public static native Long getAsset(long worldPtr, String label);
+    public static native void quit(long commandBufferPtr);
+}
diff --git a/src/jvmMain/kotlin/com/dropbear/DynamicLibraryLoader.java b/src/jvmMain/kotlin/com/dropbear/DynamicLibraryLoader.java
deleted file mode 100644
index e7aa643..0000000
--- a/src/jvmMain/kotlin/com/dropbear/DynamicLibraryLoader.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.dropbear;
-
-/// Interface for dynamic library loading, allowing for custom components not within the dropbear component
-/// library.
-public interface DynamicLibraryLoader {
-    /// Ensures that the library is loaded before accessing
-    /// any of the JNI static functions.
-    void ensureLoaded();
-
-    /// Forces the library to have a loaded boolean variable.
-    boolean isLoaded();
-}
diff --git a/src/jvmMain/kotlin/com/dropbear/EntityRefNative.java b/src/jvmMain/kotlin/com/dropbear/EntityRefNative.java
new file mode 100644
index 0000000..6e2a124
--- /dev/null
+++ b/src/jvmMain/kotlin/com/dropbear/EntityRefNative.java
@@ -0,0 +1,7 @@
+package com.dropbear;
+
+public class EntityRefNative {
+    static {
+        new EucalyptusCoreLoader().ensureLoaded();
+    }
+}
diff --git a/src/jvmMain/kotlin/com/dropbear/EntityTransform.jvm.kt b/src/jvmMain/kotlin/com/dropbear/EntityTransform.jvm.kt
deleted file mode 100644
index 4291a56..0000000
--- a/src/jvmMain/kotlin/com/dropbear/EntityTransform.jvm.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.dropbear
-
-import com.dropbear.math.Transform
-
-actual fun EntityTransform.getLocalTransform(entityId: EntityId): Transform {
-    TODO("Not yet implemented")
-}
-
-actual fun EntityTransform.setLocalTransform(
-    entityId: EntityId,
-    transform: Transform
-) {
-}
-
-actual fun EntityTransform.getWorldTransform(entityId: EntityId): Transform {
-    TODO("Not yet implemented")
-}
-
-actual fun EntityTransform.setWorldTransform(
-    entityId: EntityId,
-    transform: Transform
-) {
-}
-
-actual fun EntityTransform.propagateTransform(entityId: EntityId): Transform {
-    TODO("Not yet implemented")
-}
-
-actual fun entityTransformExistsForEntity(entityId: EntityId): Boolean {
-    TODO("Not yet implemented")
-}
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/EucalyptusCoreLoader.java b/src/jvmMain/kotlin/com/dropbear/EucalyptusCoreLoader.java
index 7cf5c14..5cf3705 100644
--- a/src/jvmMain/kotlin/com/dropbear/EucalyptusCoreLoader.java
+++ b/src/jvmMain/kotlin/com/dropbear/EucalyptusCoreLoader.java
@@ -1,5 +1,7 @@
 package com.dropbear;
 
+import com.dropbear.ffi.DynamicLibraryLoader;
+
 import java.lang.System;
 
 public class EucalyptusCoreLoader implements DynamicLibraryLoader {
diff --git a/src/jvmMain/kotlin/com/dropbear/MeshRenderer.jvm.kt b/src/jvmMain/kotlin/com/dropbear/MeshRenderer.jvm.kt
deleted file mode 100644
index b41d5dc..0000000
--- a/src/jvmMain/kotlin/com/dropbear/MeshRenderer.jvm.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.dropbear
-
-import com.dropbear.asset.ModelHandle
-import com.dropbear.asset.TextureHandle
-
-actual fun MeshRenderer.getModel(id: EntityId): ModelHandle? {
-    TODO("Not yet implemented")
-}
-
-actual fun MeshRenderer.setModel(id: EntityId, model: ModelHandle?) {
-}
-
-actual fun MeshRenderer.getAllTextureIds(id: EntityId): List<TextureHandle>? {
-    TODO("Not yet implemented")
-}
-
-actual fun MeshRenderer.getMaterialNames(id: EntityId): List<String> {
-    TODO("Not yet implemented")
-}
-
-actual fun MeshRenderer.setMaterialNames(id: EntityId, names: Array<String>) {
-}
-
-actual fun MeshRenderer.getTexture(id: EntityId, materialName: String): Long {
-    TODO("Not yet implemented")
-}
-
-actual fun MeshRenderer.setTextureOverride(
-    id: EntityId,
-    materialName: String,
-    textureHandle: Long
-) {
-}
-
-actual fun meshRendererExistsForEntity(entityId: EntityId): Boolean {
-    TODO("Not yet implemented")
-}
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/asset/AssetHandle.jvm.kt b/src/jvmMain/kotlin/com/dropbear/asset/AssetHandle.jvm.kt
index 983549e..477b388 100644
--- a/src/jvmMain/kotlin/com/dropbear/asset/AssetHandle.jvm.kt
+++ b/src/jvmMain/kotlin/com/dropbear/asset/AssetHandle.jvm.kt
@@ -1,9 +1,11 @@
 package com.dropbear.asset
 
-actual fun AssetHandle.asTextureHandle(): TextureHandle? {
-    TODO("Not yet implemented")
-}
+import com.dropbear.DropbearEngine
 
 actual fun isModelHandle(id: Long): Boolean {
-    TODO("Not yet implemented")
+    return AssetHandleNative.isModelHandle(DropbearEngine.native.assetHandle, id)
+}
+
+actual fun isTextureHandle(id: Long): Boolean {
+    return AssetHandleNative.isTextureHandle(DropbearEngine.native.assetHandle, id)
 }
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/asset/AssetHandleNative.java b/src/jvmMain/kotlin/com/dropbear/asset/AssetHandleNative.java
new file mode 100644
index 0000000..adc49b0
--- /dev/null
+++ b/src/jvmMain/kotlin/com/dropbear/asset/AssetHandleNative.java
@@ -0,0 +1,12 @@
+package com.dropbear.asset;
+
+import com.dropbear.EucalyptusCoreLoader;
+
+public class AssetHandleNative {
+    static {
+        new EucalyptusCoreLoader().ensureLoaded();
+    }
+
+    public static native boolean isModelHandle(long assetRegistryHandle, long handle);
+    public static native boolean isTextureHandle(long assetRegistryHandle, long handle);
+}
diff --git a/src/jvmMain/kotlin/com/dropbear/asset/TextureHandle.jvm.kt b/src/jvmMain/kotlin/com/dropbear/asset/TextureHandle.jvm.kt
index 9c5832c..575aa6d 100644
--- a/src/jvmMain/kotlin/com/dropbear/asset/TextureHandle.jvm.kt
+++ b/src/jvmMain/kotlin/com/dropbear/asset/TextureHandle.jvm.kt
@@ -1,5 +1,7 @@
 package com.dropbear.asset
 
+import com.dropbear.DropbearEngine
+
 actual fun TextureHandle.getTextureName(id: Long): String? {
-    TODO("Not yet implemented")
+    return TextureHandleNative.getTextureName(DropbearEngine.native.assetHandle, id)
 }
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/asset/TextureHandleNative.java b/src/jvmMain/kotlin/com/dropbear/asset/TextureHandleNative.java
new file mode 100644
index 0000000..7fc5a1c
--- /dev/null
+++ b/src/jvmMain/kotlin/com/dropbear/asset/TextureHandleNative.java
@@ -0,0 +1,11 @@
+package com.dropbear.asset;
+
+import com.dropbear.EucalyptusCoreLoader;
+
+public class TextureHandleNative {
+    static {
+        new EucalyptusCoreLoader().ensureLoaded();
+    }
+
+    public static native String getTextureName(long assetRegistryHandle, long handle);
+}
diff --git a/src/jvmMain/kotlin/com/dropbear/components/Camera.jvm.kt b/src/jvmMain/kotlin/com/dropbear/components/Camera.jvm.kt
new file mode 100644
index 0000000..64e328f
--- /dev/null
+++ b/src/jvmMain/kotlin/com/dropbear/components/Camera.jvm.kt
@@ -0,0 +1,96 @@
+package com.dropbear.components
+
+import com.dropbear.DropbearEngine
+import com.dropbear.EntityId
+import com.dropbear.math.Vector3d
+
+actual fun Camera.getCameraEye(entity: EntityId): Vector3d {
+    return CameraNative.getCameraEye(DropbearEngine.native.worldHandle, entity.raw)
+        ?: Vector3d.zero()
+}
+
+actual fun Camera.setCameraEye(entity: EntityId, value: Vector3d) {
+    CameraNative.setCameraEye(DropbearEngine.native.worldHandle, entity.raw, value)
+}
+
+actual fun Camera.getCameraTarget(entity: EntityId): Vector3d {
+    return CameraNative.getCameraTarget(DropbearEngine.native.worldHandle, entity.raw)
+        ?: Vector3d.zero()
+}
+
+actual fun Camera.setCameraTarget(entity: EntityId, value: Vector3d) {
+    CameraNative.setCameraTarget(DropbearEngine.native.worldHandle, entity.raw, value)
+}
+
+actual fun Camera.getCameraUp(entity: EntityId): Vector3d {
+    return CameraNative.getCameraUp(DropbearEngine.native.worldHandle, entity.raw)
+        ?: Vector3d.up()
+}
+
+actual fun Camera.setCameraUp(entity: EntityId, value: Vector3d) {
+    CameraNative.setCameraUp(DropbearEngine.native.worldHandle, entity.raw, value)
+}
+
+actual fun Camera.getCameraAspect(entity: EntityId): Double {
+    return CameraNative.getCameraAspect(DropbearEngine.native.worldHandle, entity.raw)
+}
+
+actual fun Camera.getCameraFovY(entity: EntityId): Double {
+    return CameraNative.getCameraFovY(DropbearEngine.native.worldHandle, entity.raw)
+}
+
+actual fun Camera.setCameraFovY(entity: EntityId, value: Double) {
+    CameraNative.setCameraFovY(DropbearEngine.native.worldHandle, entity.raw, value)
+}
+
+actual fun Camera.getCameraZNear(entity: EntityId): Double {
+    return CameraNative.getCameraZNear(DropbearEngine.native.worldHandle, entity.raw)
+}
+
+actual fun Camera.setCameraZNear(entity: EntityId, value: Double) {
+    CameraNative.setCameraZNear(DropbearEngine.native.worldHandle, entity.raw, value)
+}
+
+actual fun Camera.getCameraZFar(entity: EntityId): Double {
+    return CameraNative.getCameraZFar(DropbearEngine.native.worldHandle, entity.raw)
+}
+
+actual fun Camera.setCameraZFar(entity: EntityId, value: Double) {
+    CameraNative.setCameraZFar(DropbearEngine.native.worldHandle, entity.raw, value)
+}
+
+actual fun Camera.getCameraYaw(entity: EntityId): Double {
+    return CameraNative.getCameraYaw(DropbearEngine.native.worldHandle, entity.raw)
+}
+
+actual fun Camera.setCameraYaw(entity: EntityId, value: Double) {
+    CameraNative.setCameraYaw(DropbearEngine.native.worldHandle, entity.raw, value)
+}
+
+actual fun Camera.getCameraPitch(entity: EntityId): Double {
+    return CameraNative.getCameraPitch(DropbearEngine.native.worldHandle, entity.raw)
+}
+
+actual fun Camera.setCameraPitch(entity: EntityId, value: Double) {
+    CameraNative.setCameraPitch(DropbearEngine.native.worldHandle, entity.raw, value)
+}
+
+actual fun Camera.getCameraSpeed(entity: EntityId): Double {
+    return CameraNative.getCameraSpeed(DropbearEngine.native.worldHandle, entity.raw)
+}
+
+actual fun Camera.setCameraSpeed(entity: EntityId, value: Double) {
+    CameraNative.setCameraSpeed(DropbearEngine.native.worldHandle, entity.raw, value)
+}
+
+actual fun Camera.getCameraSensitivity(entity: EntityId): Double {
+    return CameraNative.getCameraSensitivity(DropbearEngine.native.worldHandle, entity.raw)
+}
+
+actual fun Camera.setCameraSensitivity(entity: EntityId, value: Double) {
+    CameraNative.setCameraSensitivity(DropbearEngine.native.worldHandle, entity.raw, value)
+}
+
+actual fun cameraExistsForEntity(entity: EntityId): Boolean {
+    return CameraNative.cameraExistsForEntity(DropbearEngine.native.worldHandle, entity.raw)
+}
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/components/CameraNative.java b/src/jvmMain/kotlin/com/dropbear/components/CameraNative.java
new file mode 100644
index 0000000..969c2ff
--- /dev/null
+++ b/src/jvmMain/kotlin/com/dropbear/components/CameraNative.java
@@ -0,0 +1,44 @@
+package com.dropbear.components;
+
+import com.dropbear.EucalyptusCoreLoader;
+import com.dropbear.math.Vector3d;
+
+public class CameraNative {
+    static {
+        new EucalyptusCoreLoader().ensureLoaded();
+    }
+
+    public static native boolean cameraExistsForEntity(long worldHandle, long entityId);
+
+    public static native Vector3d getCameraEye(long worldHandle, long entityId);
+    public static native void setCameraEye(long worldHandle, long entityId, Vector3d value);
+
+    public static native Vector3d getCameraTarget(long worldHandle, long entityId);
+    public static native void setCameraTarget(long worldHandle, long entityId, Vector3d value);
+
+    public static native Vector3d getCameraUp(long worldHandle, long entityId);
+    public static native void setCameraUp(long worldHandle, long entityId, Vector3d value);
+
+    public static native double getCameraAspect(long worldHandle, long entityId);
+
+    public static native double getCameraFovY(long worldHandle, long entityId);
+    public static native void setCameraFovY(long worldHandle, long entityId, double value);
+
+    public static native double getCameraZNear(long worldHandle, long entityId);
+    public static native void setCameraZNear(long worldHandle, long entityId, double value);
+
+    public static native double getCameraZFar(long worldHandle, long entityId);
+    public static native void setCameraZFar(long worldHandle, long entityId, double value);
+
+    public static native double getCameraYaw(long worldHandle, long entityId);
+    public static native void setCameraYaw(long worldHandle, long entityId, double value);
+
+    public static native double getCameraPitch(long worldHandle, long entityId);
+    public static native void setCameraPitch(long worldHandle, long entityId, double value);
+
+    public static native double getCameraSpeed(long worldHandle, long entityId);
+    public static native void setCameraSpeed(long worldHandle, long entityId, double value);
+
+    public static native double getCameraSensitivity(long worldHandle, long entityId);
+    public static native void setCameraSensitivity(long worldHandle, long entityId, double value);
+}
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/components/CustomProperties.jvm.kt b/src/jvmMain/kotlin/com/dropbear/components/CustomProperties.jvm.kt
new file mode 100644
index 0000000..086d64a
--- /dev/null
+++ b/src/jvmMain/kotlin/com/dropbear/components/CustomProperties.jvm.kt
@@ -0,0 +1,103 @@
+package com.dropbear.components
+
+import com.dropbear.DropbearEngine
+import com.dropbear.EntityId
+import com.dropbear.math.Vector3d
+
+actual fun CustomProperties.getStringProperty(
+    entityHandle: Long,
+    label: String
+): String? {
+    return CustomPropertiesNative.getStringProperty(DropbearEngine.native.worldHandle, entityHandle, label)
+}
+
+actual fun CustomProperties.getIntProperty(entityHandle: Long, label: String): Int? {
+    return CustomPropertiesNative.getIntProperty(DropbearEngine.native.worldHandle, entityHandle, label)
+}
+
+actual fun CustomProperties.getLongProperty(
+    entityHandle: Long,
+    label: String
+): Long? {
+    return CustomPropertiesNative.getLongProperty(DropbearEngine.native.worldHandle, entityHandle, label)
+}
+
+actual fun CustomProperties.getDoubleProperty(
+    entityHandle: Long,
+    label: String
+): Double? {
+    return CustomPropertiesNative.getDoubleProperty(DropbearEngine.native.worldHandle, entityHandle, label)
+}
+
+actual fun CustomProperties.getFloatProperty(
+    entityHandle: Long,
+    label: String
+): Float? {
+    return CustomPropertiesNative.getFloatProperty(DropbearEngine.native.worldHandle, entityHandle, label)
+}
+
+actual fun CustomProperties.getBoolProperty(
+    entityHandle: Long,
+    label: String
+): Boolean? {
+    return CustomPropertiesNative.getBoolProperty(DropbearEngine.native.worldHandle, entityHandle, label)
+}
+
+actual fun CustomProperties.getVec3Property(
+    entityHandle: Long,
+    label: String
+): Vector3d? {
+    return CustomPropertiesNative.getVec3Property(DropbearEngine.native.worldHandle, entityHandle, label)
+}
+
+actual fun CustomProperties.setStringProperty(
+    entityHandle: Long,
+    label: String,
+    value: String
+) {
+    CustomPropertiesNative.setStringProperty(DropbearEngine.native.worldHandle, entityHandle, label, value)
+}
+
+actual fun CustomProperties.setIntProperty(
+    entityHandle: Long,
+    label: String,
+    value: Int
+) {
+    CustomPropertiesNative.setIntProperty(DropbearEngine.native.worldHandle, entityHandle, label, value)
+}
+
+actual fun CustomProperties.setLongProperty(
+    entityHandle: Long,
+    label: String,
+    value: Long
+) {
+    CustomPropertiesNative.setLongProperty(DropbearEngine.native.worldHandle, entityHandle, label, value)
+}
+
+actual fun CustomProperties.setFloatProperty(
+    entityHandle: Long,
+    label: String,
+    value: Double
+) {
+    CustomPropertiesNative.setFloatProperty(DropbearEngine.native.worldHandle, entityHandle, label, value)
+}
+
+actual fun CustomProperties.setBoolProperty(
+    entityHandle: Long,
+    label: String,
+    value: Boolean
+) {
+    CustomPropertiesNative.setBoolProperty(DropbearEngine.native.worldHandle, entityHandle, label, value)
+}
+
+actual fun CustomProperties.setVec3Property(
+    entityHandle: Long,
+    label: String,
+    value: Vector3d
+) {
+    CustomPropertiesNative.setVec3Property(DropbearEngine.native.worldHandle, entityHandle, label, value)
+}
+
+actual fun customPropertiesExistsForEntity(entityId: EntityId): Boolean {
+    return CustomPropertiesNative.customPropertiesExistsForEntity(DropbearEngine.native.worldHandle, entityId.raw)
+}
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/components/CustomPropertiesNative.java b/src/jvmMain/kotlin/com/dropbear/components/CustomPropertiesNative.java
new file mode 100644
index 0000000..e1775c0
--- /dev/null
+++ b/src/jvmMain/kotlin/com/dropbear/components/CustomPropertiesNative.java
@@ -0,0 +1,27 @@
+package com.dropbear.components;
+
+import com.dropbear.EucalyptusCoreLoader;
+import com.dropbear.math.Vector3d;
+
+public class CustomPropertiesNative {
+    static {
+        new EucalyptusCoreLoader().ensureLoaded();
+    }
+
+    public static native boolean customPropertiesExistsForEntity(long worldHandle, long entityId);
+
+    public static native String getStringProperty(long worldHandle, long entityId, String label);
+    public static native Integer getIntProperty(long worldHandle, long entityId, String label);
+    public static native Long getLongProperty(long worldHandle, long entityId, String label);
+    public static native Double getDoubleProperty(long worldHandle, long entityId, String label);
+    public static native Float getFloatProperty(long worldHandle, long entityId, String label);
+    public static native Boolean getBoolProperty(long worldHandle, long entityId, String label);
+    public static native Vector3d getVec3Property(long worldHandle, long entityId, String label);
+
+    public static native void setStringProperty(long worldHandle, long entityId, String label, String value);
+    public static native void setIntProperty(long worldHandle, long entityId, String label, int value);
+    public static native void setLongProperty(long worldHandle, long entityId, String label, long value);
+    public static native void setFloatProperty(long worldHandle, long entityId, String label, double value);
+    public static native void setBoolProperty(long worldHandle, long entityId, String label, boolean value);
+    public static native void setVec3Property(long worldHandle, long entityId, String label, Vector3d value);
+}
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/components/EntityTransform.jvm.kt b/src/jvmMain/kotlin/com/dropbear/components/EntityTransform.jvm.kt
new file mode 100644
index 0000000..ae1912d
--- /dev/null
+++ b/src/jvmMain/kotlin/com/dropbear/components/EntityTransform.jvm.kt
@@ -0,0 +1,43 @@
+package com.dropbear.components
+
+import com.dropbear.DropbearEngine
+import com.dropbear.EntityId
+import com.dropbear.math.Transform
+
+actual fun entityTransformExistsForEntity(entityId: EntityId): Boolean {
+    return EntityTransformNative.entityTransformExistsForEntity(DropbearEngine.native.worldHandle, entityId.raw)
+}
+
+actual fun EntityTransform.getLocalTransform(entityId: EntityId): Transform {
+    return EntityTransformNative.getLocalTransform(DropbearEngine.native.worldHandle, entityId.raw)
+}
+
+actual fun EntityTransform.setLocalTransform(
+    entityId: EntityId,
+    transform: Transform
+) {
+    EntityTransformNative.setLocalTransform(
+        DropbearEngine.native.worldHandle,
+        entityId.raw,
+        transform
+    )
+}
+
+actual fun EntityTransform.getWorldTransform(entityId: EntityId): Transform {
+    return EntityTransformNative.getWorldTransform(DropbearEngine.native.worldHandle, entityId.raw)
+}
+
+actual fun EntityTransform.setWorldTransform(
+    entityId: EntityId,
+    transform: Transform
+) {
+    EntityTransformNative.setWorldTransform(
+        DropbearEngine.native.worldHandle,
+        entityId.raw,
+        transform
+    )
+}
+
+actual fun EntityTransform.propagateTransform(entityId: EntityId): Transform {
+    return EntityTransformNative.propagateTransform(DropbearEngine.native.worldHandle, entityId.raw)
+}
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/components/EntityTransformNative.java b/src/jvmMain/kotlin/com/dropbear/components/EntityTransformNative.java
new file mode 100644
index 0000000..37520f7
--- /dev/null
+++ b/src/jvmMain/kotlin/com/dropbear/components/EntityTransformNative.java
@@ -0,0 +1,18 @@
+package com.dropbear.components;
+
+import com.dropbear.EucalyptusCoreLoader;
+import com.dropbear.math.Transform;
+
+public class EntityTransformNative {
+    static {
+        new EucalyptusCoreLoader().ensureLoaded();
+    }
+
+    public static native boolean entityTransformExistsForEntity(long worldPtr, long entityId);
+
+    public static native Transform getLocalTransform(long worldPtr, long entityId);
+    public static native void setLocalTransform(long worldPtr, long entityId, Transform transform);
+    public static native Transform getWorldTransform(long worldPtr, long entityId);
+    public static native void setWorldTransform(long worldPtr, long entityId, Transform transform);
+    public static native Transform propagateTransform(long worldPtr, long entityId);
+}
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/components/MeshRenderer.jvm.kt b/src/jvmMain/kotlin/com/dropbear/components/MeshRenderer.jvm.kt
new file mode 100644
index 0000000..20427f0
--- /dev/null
+++ b/src/jvmMain/kotlin/com/dropbear/components/MeshRenderer.jvm.kt
@@ -0,0 +1,60 @@
+package com.dropbear.components
+
+import com.dropbear.DropbearEngine
+import com.dropbear.EntityId
+import com.dropbear.asset.ModelHandle
+import com.dropbear.asset.TextureHandle
+
+actual fun MeshRenderer.getModel(id: EntityId): ModelHandle? {
+    return ModelHandle(MeshRendererNative.getModel(DropbearEngine.native.worldHandle, id.raw))
+}
+
+actual fun MeshRenderer.setModel(id: EntityId, model: ModelHandle?) {
+    if (model == null) {
+        MeshRendererNative.setModel(DropbearEngine.native.worldHandle, id.raw, 0L)
+        return
+    }
+
+    return MeshRendererNative.setModel(
+        DropbearEngine.native.worldHandle,
+        id.raw,
+        model.raw()
+    )
+}
+
+actual fun MeshRenderer.getAllTextureIds(id: EntityId): List<TextureHandle>? {
+    val textureHandles = MeshRendererNative.getAllTextureIds(
+        DropbearEngine.native.worldHandle,
+        id.raw
+    ) ?: return null
+
+    return textureHandles.map { TextureHandle(it) }
+}
+
+actual fun MeshRenderer.getTexture(id: EntityId, materialName: String): Long {
+    return MeshRendererNative.getTexture(
+        DropbearEngine.native.worldHandle,
+        id.raw,
+        materialName
+    )
+}
+
+actual fun MeshRenderer.setTextureOverride(
+    id: EntityId,
+    materialName: String,
+    textureHandle: Long
+) {
+    return MeshRendererNative.setTextureOverride(
+        DropbearEngine.native.worldHandle,
+        id.raw,
+        materialName,
+        textureHandle
+    )
+}
+
+actual fun meshRendererExistsForEntity(entityId: EntityId): Boolean {
+    return MeshRendererNative.meshRendererExistsForEntity(
+        DropbearEngine.native.worldHandle,
+        entityId.raw
+    )
+}
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/components/MeshRendererNative.java b/src/jvmMain/kotlin/com/dropbear/components/MeshRendererNative.java
new file mode 100644
index 0000000..2918d24
--- /dev/null
+++ b/src/jvmMain/kotlin/com/dropbear/components/MeshRendererNative.java
@@ -0,0 +1,17 @@
+package com.dropbear.components;
+
+import com.dropbear.EucalyptusCoreLoader;
+
+public class MeshRendererNative {
+    static {
+        new EucalyptusCoreLoader().ensureLoaded();
+    }
+
+    public static native boolean meshRendererExistsForEntity(long worldHandle, long entityId);
+
+    public static native long getModel(long worldHandle, long entityId);
+    public static native void setModel(long worldHandle, long entityId, long modelHandle);
+    public static native long[] getAllTextureIds(long worldHandle, long entityId);
+    public static native long getTexture(long worldHandle, long entityId, String materialName);
+    public static native void setTextureOverride(long worldHandle, long entityId, String materialName, long textureHandle);
+}
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/ffi/DynamicLibraryLoader.java b/src/jvmMain/kotlin/com/dropbear/ffi/DynamicLibraryLoader.java
new file mode 100644
index 0000000..43b5c17
--- /dev/null
+++ b/src/jvmMain/kotlin/com/dropbear/ffi/DynamicLibraryLoader.java
@@ -0,0 +1,12 @@
+package com.dropbear.ffi;
+
+/// Interface for dynamic library loading, allowing for custom components not within the dropbear component
+/// library.
+public interface DynamicLibraryLoader {
+    /// Ensures that the library is loaded before accessing
+    /// any of the JNI static functions.
+    void ensureLoaded();
+
+    /// Forces the library to have a loaded boolean variable.
+    boolean isLoaded();
+}
diff --git a/src/jvmMain/kotlin/com/dropbear/input/Gamepad.jvm.kt b/src/jvmMain/kotlin/com/dropbear/input/Gamepad.jvm.kt
index ea1c67c..9c7d2e0 100644
--- a/src/jvmMain/kotlin/com/dropbear/input/Gamepad.jvm.kt
+++ b/src/jvmMain/kotlin/com/dropbear/input/Gamepad.jvm.kt
@@ -1,8 +1,35 @@
 package com.dropbear.input
 
+import com.dropbear.DropbearEngine
+import com.dropbear.math.Vector2d
+
 actual fun Gamepad.isGamepadButtonPressed(
     id: Long,
     button: GamepadButton
 ): Boolean {
-    TODO("Not yet implemented")
+    return GamepadNative.isGamepadButtonPressed(
+        DropbearEngine.native.inputHandle,
+        id,
+        button.ordinal
+    )
+}
+
+@Suppress("UNCHECKED_CAST")
+actual fun Gamepad.getLeftStickPosition(id: Long): Vector2d {
+    val result = GamepadNative.getLeftStickPosition(
+        DropbearEngine.native.inputHandle,
+        id
+    )
+
+    return result ?: Vector2d.zero()
+}
+
+@Suppress("UNCHECKED_CAST")
+actual fun Gamepad.getRightStickPosition(id: Long): Vector2d {
+    val result = GamepadNative.getRightStickPosition(
+        DropbearEngine.native.inputHandle,
+        id
+    )
+
+    return result ?: Vector2d.zero()
 }
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/input/GamepadNative.java b/src/jvmMain/kotlin/com/dropbear/input/GamepadNative.java
new file mode 100644
index 0000000..0ee5294
--- /dev/null
+++ b/src/jvmMain/kotlin/com/dropbear/input/GamepadNative.java
@@ -0,0 +1,15 @@
+package com.dropbear.input;
+
+import com.dropbear.EucalyptusCoreLoader;
+import com.dropbear.math.Vector2;
+import com.dropbear.math.Vector2d;
+
+public class GamepadNative {
+    static {
+        new EucalyptusCoreLoader().ensureLoaded();
+    }
+
+    public static native boolean isGamepadButtonPressed(long inputStateHandle, long gamepad, int gamepadButton);
+    public static native Vector2d getLeftStickPosition(long inputStateHandle, long gamepad);
+    public static native Vector2d getRightStickPosition(long inputStateHandle, long gamepad);
+}
diff --git a/src/jvmMain/kotlin/com/dropbear/input/InputState.jvm.kt b/src/jvmMain/kotlin/com/dropbear/input/InputState.jvm.kt
index d41379b..30dffa8 100644
--- a/src/jvmMain/kotlin/com/dropbear/input/InputState.jvm.kt
+++ b/src/jvmMain/kotlin/com/dropbear/input/InputState.jvm.kt
@@ -1,46 +1,51 @@
 package com.dropbear.input
 
-import com.dropbear.math.Vector2D
+import com.dropbear.DropbearEngine
+import com.dropbear.math.Vector2d
 
 actual class InputState actual constructor() {
     actual fun printInputState() {
+        return InputStateNative.printInputState(DropbearEngine.native.inputHandle)
     }
 
     actual fun isKeyPressed(key: KeyCode): Boolean {
-        TODO("Not yet implemented")
+        return InputStateNative.isKeyPressed(DropbearEngine.native.inputHandle, key.ordinal)
     }
 
-    actual fun getMousePosition(): Vector2D {
-        TODO("Not yet implemented")
+    actual fun getMousePosition(): Vector2d {
+        return InputStateNative.getMousePosition(DropbearEngine.native.inputHandle)
     }
 
     actual fun isMouseButtonPressed(button: MouseButton): Boolean {
-        TODO("Not yet implemented")
+        return InputStateNative.isMouseButtonPressed(DropbearEngine.native.inputHandle, button)
     }
 
-    actual fun getMouseDelta(): Vector2D {
-        TODO("Not yet implemented")
+    actual fun getMouseDelta(): Vector2d {
+        return InputStateNative.getMouseDelta(DropbearEngine.native.inputHandle)
     }
 
     actual fun isCursorLocked(): Boolean {
-        TODO("Not yet implemented")
+        return InputStateNative.isCursorLocked(DropbearEngine.native.inputHandle)
     }
 
     actual fun setCursorLocked(locked: Boolean) {
+        return InputStateNative.setCursorLocked(DropbearEngine.native.commandBufferHandle, DropbearEngine.native.inputHandle, locked)
     }
 
-    actual fun getLastMousePos(): Vector2D {
-        TODO("Not yet implemented")
+    actual fun getLastMousePos(): Vector2d {
+        return InputStateNative.getLastMousePos(DropbearEngine.native.inputHandle)
     }
 
     actual fun isCursorHidden(): Boolean {
-        TODO("Not yet implemented")
+        return InputStateNative.isCursorHidden(DropbearEngine.native.inputHandle)
     }
 
     actual fun setCursorHidden(hidden: Boolean) {
+        return InputStateNative.setCursorHidden(DropbearEngine.native.commandBufferHandle, DropbearEngine.native.inputHandle, hidden)
     }
 
     actual fun getConnectedGamepads(): List<Gamepad> {
-        TODO("Not yet implemented")
+        val result = InputStateNative.getConnectedGamepads(DropbearEngine.native.inputHandle)
+        return result.map { Gamepad(it) }.toList()
     }
 }
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/input/InputStateNative.java b/src/jvmMain/kotlin/com/dropbear/input/InputStateNative.java
new file mode 100644
index 0000000..1f47bc3
--- /dev/null
+++ b/src/jvmMain/kotlin/com/dropbear/input/InputStateNative.java
@@ -0,0 +1,22 @@
+package com.dropbear.input;
+
+import com.dropbear.EucalyptusCoreLoader;
+import com.dropbear.math.Vector2d;
+
+public class InputStateNative {
+    static {
+        new EucalyptusCoreLoader().ensureLoaded();
+    }
+
+    public static native void printInputState(long inputStateHandle);
+    public static native boolean isKeyPressed(long inputStateHandle, int keyCode);
+    public static native Vector2d getMousePosition(long inputStateHandle);
+    public static native boolean isMouseButtonPressed(long inputStateHandle, MouseButton mouseButton);
+    public static native Vector2d getMouseDelta(long inputStateHandle);
+    public static native boolean isCursorLocked(long inputStateHandle);
+    public static native void setCursorLocked(long commandBufferPtr, long inputStateHandle, boolean locked);
+    public static native Vector2d getLastMousePos(long inputStateHandle);
+    public static native boolean isCursorHidden(long inputStateHandle);
+    public static native void setCursorHidden(long commandBufferPtr, long inputStateHandle, boolean hidden);
+    public static native long[] getConnectedGamepads(long inputStateHandle);
+}
diff --git a/src/jvmMain/kotlin/com/dropbear/physics/Collider.jvm.kt b/src/jvmMain/kotlin/com/dropbear/physics/Collider.jvm.kt
index f711398..f306c88 100644
--- a/src/jvmMain/kotlin/com/dropbear/physics/Collider.jvm.kt
+++ b/src/jvmMain/kotlin/com/dropbear/physics/Collider.jvm.kt
@@ -1,80 +1,91 @@
 package com.dropbear.physics
 
-import com.dropbear.math.Vector3D
+import com.dropbear.DropbearEngine
+import com.dropbear.math.Vector3d
 
 actual fun Collider.getColliderShape(collider: Collider): ColliderShape {
-    TODO("Not yet implemented")
+    return ColliderNative.getColliderShape(DropbearEngine.native.physicsEngineHandle, this)
 }
 
 actual fun Collider.setColliderShape(
     collider: Collider,
     shape: ColliderShape
 ) {
+    ColliderNative.setColliderShape(DropbearEngine.native.physicsEngineHandle, this, shape)
+}
+
+actual fun Collider.getColliderDensity(collider: Collider): Double {
+    return ColliderNative.getColliderDensity(DropbearEngine.native.physicsEngineHandle, this)
 }
 
 actual fun Collider.setColliderDensity(
     collider: Collider,
     density: Double
 ) {
+    ColliderNative.setColliderDensity(DropbearEngine.native.physicsEngineHandle, this, density)
 }
 
 actual fun Collider.getColliderFriction(collider: Collider): Double {
-    TODO("Not yet implemented")
+    return ColliderNative.getColliderFriction(DropbearEngine.native.physicsEngineHandle, this)
 }
 
 actual fun Collider.setColliderFriction(
     collider: Collider,
     friction: Double
 ) {
+    ColliderNative.setColliderFriction(DropbearEngine.native.physicsEngineHandle, this, friction)
 }
 
 actual fun Collider.getColliderRestitution(collider: Collider): Double {
-    TODO("Not yet implemented")
+    return ColliderNative.getColliderRestitution(DropbearEngine.native.physicsEngineHandle, this)
 }
 
 actual fun Collider.setColliderRestitution(
     collider: Collider,
     restitution: Double
 ) {
+    ColliderNative.setColliderRestitution(DropbearEngine.native.physicsEngineHandle, this, restitution)
 }
 
 actual fun Collider.getColliderIsSensor(collider: Collider): Boolean {
-    TODO("Not yet implemented")
+    return ColliderNative.getColliderIsSensor(DropbearEngine.native.physicsEngineHandle, this)
 }
 
 actual fun Collider.setColliderIsSensor(
     collider: Collider,
     isSensor: Boolean
 ) {
+    ColliderNative.setColliderIsSensor(DropbearEngine.native.physicsEngineHandle, this, isSensor)
 }
 
-actual fun Collider.getColliderTranslation(collider: Collider): Vector3D {
-    TODO("Not yet implemented")
+actual fun Collider.getColliderTranslation(collider: Collider): Vector3d {
+    return ColliderNative.getColliderTranslation(DropbearEngine.native.physicsEngineHandle, this)
+        ?: Vector3d.zero()
 }
 
 actual fun Collider.setColliderTranslation(
     collider: Collider,
-    translation: Vector3D
+    translation: Vector3d
 ) {
+    ColliderNative.setColliderTranslation(DropbearEngine.native.physicsEngineHandle, this, translation)
+}
+
+actual fun Collider.getColliderRotation(collider: Collider): Vector3d {
+    return ColliderNative.getColliderRotation(DropbearEngine.native.physicsEngineHandle, this)
+        ?: Vector3d.zero()
 }
 
 actual fun Collider.setColliderRotation(
     collider: Collider,
-    rotation: Vector3D
+    rotation: Vector3d
 ) {
-}
-
-actual fun Collider.getColliderRotation(collider: Collider): Vector3D {
-    TODO("Not yet implemented")
+    ColliderNative.setColliderRotation(DropbearEngine.native.physicsEngineHandle, this, rotation)
 }
 
 actual fun Collider.getColliderMass(collider: Collider): Double {
-    TODO("Not yet implemented")
+    return ColliderNative.getColliderMass(DropbearEngine.native.physicsEngineHandle, this)
 }
 
 actual fun Collider.setColliderMass(collider: Collider, mass: Double) {
-}
-
-actual fun Collider.getColliderDensity(collider: Collider): Double {
-    TODO("Not yet implemented")
+    ColliderNative.setColliderMass(DropbearEngine.native.physicsEngineHandle, this, mass)
 }
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/physics/ColliderGroup.jvm.kt b/src/jvmMain/kotlin/com/dropbear/physics/ColliderGroup.jvm.kt
index 24537dc..2f74089 100644
--- a/src/jvmMain/kotlin/com/dropbear/physics/ColliderGroup.jvm.kt
+++ b/src/jvmMain/kotlin/com/dropbear/physics/ColliderGroup.jvm.kt
@@ -1,11 +1,12 @@
 package com.dropbear.physics
 
+import com.dropbear.DropbearEngine
 import com.dropbear.EntityId
 
 actual fun ColliderGroup.getColliderGroupColliders(colliderGroup: ColliderGroup): List<Collider> {
-    TODO("Not yet implemented")
+    return ColliderGroupNative.getColliderGroupColliders(DropbearEngine.native.physicsEngineHandle, colliderGroup).toList()
 }
 
 actual fun colliderGroupExistsForEntity(entityId: EntityId): Boolean {
-    TODO("Not yet implemented")
+    return ColliderGroupNative.colliderGroupExistsForEntity(DropbearEngine.native.worldHandle, entityId.raw)
 }
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/physics/ColliderGroupNative.java b/src/jvmMain/kotlin/com/dropbear/physics/ColliderGroupNative.java
new file mode 100644
index 0000000..40b10f6
--- /dev/null
+++ b/src/jvmMain/kotlin/com/dropbear/physics/ColliderGroupNative.java
@@ -0,0 +1,12 @@
+package com.dropbear.physics;
+
+import com.dropbear.EucalyptusCoreLoader;
+
+public class ColliderGroupNative {
+    static {
+        new EucalyptusCoreLoader().ensureLoaded();
+    }
+
+    public static native Collider[] getColliderGroupColliders(long physicsPtr, ColliderGroup colliderGroup);
+    public static native boolean colliderGroupExistsForEntity(long worldPtr, long entityId);
+}
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/physics/ColliderNative.java b/src/jvmMain/kotlin/com/dropbear/physics/ColliderNative.java
new file mode 100644
index 0000000..e1a2052
--- /dev/null
+++ b/src/jvmMain/kotlin/com/dropbear/physics/ColliderNative.java
@@ -0,0 +1,34 @@
+package com.dropbear.physics;
+
+import com.dropbear.EucalyptusCoreLoader;
+import com.dropbear.math.Vector3d;
+
+public class ColliderNative {
+    static {
+        new EucalyptusCoreLoader().ensureLoaded();
+    }
+
+    public static native ColliderShape getColliderShape(long physicsPtr, Collider collider);
+    public static native void setColliderShape(long physicsPtr, Collider collider, ColliderShape shape);
+
+    public static native double getColliderDensity(long physicsPtr, Collider collider);
+    public static native void setColliderDensity(long physicsPtr, Collider collider, double density);
+
+    public static native double getColliderFriction(long physicsPtr, Collider collider);
+    public static native void setColliderFriction(long physicsPtr, Collider collider, double friction);
+
+    public static native double getColliderRestitution(long physicsPtr, Collider collider);
+    public static native void setColliderRestitution(long physicsPtr, Collider collider, double restitution);
+
+    public static native double getColliderMass(long physicsPtr, Collider collider);
+    public static native void setColliderMass(long physicsPtr, Collider collider, double mass);
+
+    public static native boolean getColliderIsSensor(long physicsPtr, Collider collider);
+    public static native void setColliderIsSensor(long physicsPtr, Collider collider, boolean isSensor);
+
+    public static native Vector3d getColliderTranslation(long physicsPtr, Collider collider);
+    public static native void setColliderTranslation(long physicsPtr, Collider collider, Vector3d translation);
+
+    public static native Vector3d getColliderRotation(long physicsPtr, Collider collider);
+    public static native void setColliderRotation(long physicsPtr, Collider collider, Vector3d rotation);
+}
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/physics/RigidBody.jvm.kt b/src/jvmMain/kotlin/com/dropbear/physics/RigidBody.jvm.kt
index c37176a..a1b3b27 100644
--- a/src/jvmMain/kotlin/com/dropbear/physics/RigidBody.jvm.kt
+++ b/src/jvmMain/kotlin/com/dropbear/physics/RigidBody.jvm.kt
@@ -1,110 +1,133 @@
 package com.dropbear.physics
 
+import com.dropbear.DropbearEngine
 import com.dropbear.EntityId
-import com.dropbear.math.Vector3D
+import com.dropbear.math.Vector3d
 
 actual fun RigidBody.getRigidbodyMode(rigidBody: RigidBody): RigidBodyMode {
-    TODO("Not yet implemented")
+    val result = RigidBodyNative.getRigidBodyMode(DropbearEngine.native.physicsEngineHandle, this)
+    return RigidBodyMode.entries[result]
 }
 
 actual fun RigidBody.setRigidbodyMode(
     rigidBody: RigidBody,
     mode: RigidBodyMode
 ) {
+    RigidBodyNative.setRigidBodyMode(DropbearEngine.native.physicsEngineHandle, this, mode.ordinal)
 }
 
 actual fun RigidBody.getRigidbodyGravityScale(rigidBody: RigidBody): Double {
-    TODO("Not yet implemented")
+    return RigidBodyNative.getRigidBodyGravityScale(DropbearEngine.native.physicsEngineHandle, this)
 }
 
 actual fun RigidBody.setRigidbodyGravityScale(
     rigidBody: RigidBody,
     gravityScale: Double
 ) {
+    RigidBodyNative.setRigidBodyGravityScale(DropbearEngine.native.physicsEngineHandle, this, gravityScale)
 }
 
 actual fun RigidBody.getRigidbodyCanSleep(rigidBody: RigidBody): Boolean {
-    TODO("Not yet implemented")
+    return RigidBodyNative.getRigidBodyCanSleep(DropbearEngine.native.physicsEngineHandle, this)
 }
 
 actual fun RigidBody.setRigidbodyCanSleep(
     rigidBody: RigidBody,
     canSleep: Boolean
 ) {
+    RigidBodyNative.setRigidBodyCanSleep(DropbearEngine.native.physicsEngineHandle, this, canSleep)
 }
 
 actual fun RigidBody.getRigidbodyCcdEnabled(rigidBody: RigidBody): Boolean {
-    TODO("Not yet implemented")
+    return RigidBodyNative.getRigidBodyCcdEnabled(DropbearEngine.native.physicsEngineHandle, this)
 }
 
 actual fun RigidBody.setRigidbodyCcdEnabled(
     rigidBody: RigidBody,
     ccdEnabled: Boolean
 ) {
+    RigidBodyNative.setRigidBodyCcdEnabled(DropbearEngine.native.physicsEngineHandle, this, ccdEnabled)
 }
 
-actual fun RigidBody.getRigidbodyLinearVelocity(rigidBody: RigidBody): Vector3D {
-    TODO("Not yet implemented")
+actual fun RigidBody.getRigidbodyLinearVelocity(rigidBody: RigidBody): Vector3d {
+    return RigidBodyNative.getRigidBodyLinearVelocity(DropbearEngine.native.physicsEngineHandle, this)
+        ?: Vector3d.zero()
 }
 
 actual fun RigidBody.setRigidbodyLinearVelocity(
     rigidBody: RigidBody,
-    linearVelocity: Vector3D
+    linearVelocity: Vector3d
 ) {
+    RigidBodyNative.setRigidBodyLinearVelocity(DropbearEngine.native.physicsEngineHandle, this, linearVelocity)
 }
 
-actual fun RigidBody.getRigidbodyAngularVelocity(rigidBody: RigidBody): Vector3D {
-    TODO("Not yet implemented")
+actual fun RigidBody.getRigidbodyAngularVelocity(rigidBody: RigidBody): Vector3d {
+    return RigidBodyNative.getRigidBodyAngularVelocity(DropbearEngine.native.physicsEngineHandle, this)
+        ?: Vector3d.zero()
 }
 
 actual fun RigidBody.setRigidbodyAngularVelocity(
     rigidBody: RigidBody,
-    angularVelocity: Vector3D
+    angularVelocity: Vector3d
 ) {
+    RigidBodyNative.setRigidBodyAngularVelocity(DropbearEngine.native.physicsEngineHandle, this, angularVelocity)
 }
 
 actual fun RigidBody.getRigidbodyLinearDamping(rigidBody: RigidBody): Double {
-    TODO("Not yet implemented")
+    return RigidBodyNative.getRigidBodyLinearDamping(DropbearEngine.native.physicsEngineHandle, this)
+}
+
+actual fun RigidBody.setRigidbodyLinearDamping(
+    rigidBody: RigidBody,
+    linearDamping: Double
+) {
+    RigidBodyNative.setRigidBodyLinearDamping(DropbearEngine.native.physicsEngineHandle, this, linearDamping)
 }
 
 actual fun RigidBody.getRigidbodyAngularDamping(rigidBody: RigidBody): Double {
-    TODO("Not yet implemented")
+    return RigidBodyNative.getRigidBodyAngularDamping(DropbearEngine.native.physicsEngineHandle, this)
 }
 
 actual fun RigidBody.setRigidbodyAngularDamping(
     rigidBody: RigidBody,
     angularDamping: Double
 ) {
+    RigidBodyNative.setRigidBodyAngularDamping(DropbearEngine.native.physicsEngineHandle, this, angularDamping)
 }
 
 actual fun RigidBody.getRigidbodyLockTranslation(rigidBody: RigidBody): AxisLock {
-    TODO("Not yet implemented")
+    return RigidBodyNative.getRigidBodyLockTranslation(DropbearEngine.native.physicsEngineHandle, this)
 }
 
 actual fun RigidBody.setRigidbodyLockTranslation(
     rigidBody: RigidBody,
     lockTranslation: AxisLock
 ) {
+    RigidBodyNative.setRigidBodyLockTranslation(DropbearEngine.native.physicsEngineHandle, this, lockTranslation)
 }
 
 actual fun RigidBody.getRigidbodyLockRotation(rigidBody: RigidBody): AxisLock {
-    TODO("Not yet implemented")
+    return RigidBodyNative.getRigidBodyLockRotation(DropbearEngine.native.physicsEngineHandle, this)
 }
 
 actual fun RigidBody.setRigidbodyLockRotation(
     rigidBody: RigidBody,
     lockRotation: AxisLock
 ) {
+    RigidBodyNative.setRigidBodyLockRotation(DropbearEngine.native.physicsEngineHandle, this, lockRotation)
 }
 
 actual fun RigidBody.getRigidbodyChildren(rigidBody: RigidBody): List<EntityId> {
-    TODO("Not yet implemented")
+    val result = RigidBodyNative.getRigidBodyChildren(DropbearEngine.native.physicsEngineHandle, this)
+    return result.map { EntityId(it) }
 }
 
 actual fun RigidBody.setRigidbodyChildren(
     rigidBody: RigidBody,
     children: List<EntityId>
 ) {
+    val ids = children.map { it.raw }.toLongArray()
+    RigidBodyNative.setRigidBodyChildren(DropbearEngine.native.physicsEngineHandle, this, ids)
 }
 
 actual fun RigidBody.applyImpulse(
@@ -113,6 +136,7 @@ actual fun RigidBody.applyImpulse(
     y: Double,
     z: Double
 ) {
+    RigidBodyNative.applyImpulse(DropbearEngine.native.physicsEngineHandle, this, x, y, z)
 }
 
 actual fun RigidBody.applyTorqueImpulse(
@@ -121,15 +145,9 @@ actual fun RigidBody.applyTorqueImpulse(
     y: Double,
     z: Double
 ) {
-}
-
-actual fun RigidBody.
-        setRigidbodyLinearDamping(
-    rigidBody: RigidBody,
-    linearDamping: Double
-) {
+    RigidBodyNative.applyTorqueImpulse(DropbearEngine.native.physicsEngineHandle, this, x, y, z)
 }
 
 actual fun rigidBodyExistsForEntity(entityId: EntityId): Index? {
-    TODO("Not yet implemented")
+    return RigidBodyNative.rigidBodyExistsForEntity(DropbearEngine.native.physicsEngineHandle, entityId.raw)
 }
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/physics/RigidBodyNative.java b/src/jvmMain/kotlin/com/dropbear/physics/RigidBodyNative.java
new file mode 100644
index 0000000..5b90ba6
--- /dev/null
+++ b/src/jvmMain/kotlin/com/dropbear/physics/RigidBodyNative.java
@@ -0,0 +1,48 @@
+package com.dropbear.physics;
+
+import com.dropbear.EucalyptusCoreLoader;
+import com.dropbear.math.Vector3d;
+
+public class RigidBodyNative {
+    static {
+        new EucalyptusCoreLoader().ensureLoaded();
+    }
+
+    public static native Index rigidBodyExistsForEntity(long physicsPtr, long entityId);
+
+    public static native int getRigidBodyMode(long physicsPtr, RigidBody rigidBody);
+    public static native void setRigidBodyMode(long physicsPtr, RigidBody rigidBody, int mode);
+
+    public static native double getRigidBodyGravityScale(long physicsPtr, RigidBody rigidBody);
+    public static native void setRigidBodyGravityScale(long physicsPtr, RigidBody rigidBody, double gravityScale);
+
+    public static native double getRigidBodyLinearDamping(long physicsPtr, RigidBody rigidBody);
+    public static native void setRigidBodyLinearDamping(long physicsPtr, RigidBody rigidBody, double linearDamping);
+
+    public static native double getRigidBodyAngularDamping(long physicsPtr, RigidBody rigidBody);
+    public static native void setRigidBodyAngularDamping(long physicsPtr, RigidBody rigidBody, double angularDamping);
+
+    public static native boolean getRigidBodyCanSleep(long physicsPtr, RigidBody rigidBody);
+    public static native void setRigidBodyCanSleep(long physicsPtr, RigidBody rigidBody, boolean canSleep);
+
+    public static native boolean getRigidBodyCcdEnabled(long physicsPtr, RigidBody rigidBody);
+    public static native void setRigidBodyCcdEnabled(long physicsPtr, RigidBody rigidBody, boolean ccdEnabled);
+
+    public static native Vector3d getRigidBodyLinearVelocity(long physicsPtr, RigidBody rigidBody);
+    public static native void setRigidBodyLinearVelocity(long physicsPtr, RigidBody rigidBody, Vector3d linearVelocity);
+
+    public static native Vector3d getRigidBodyAngularVelocity(long physicsPtr, RigidBody rigidBody);
+    public static native void setRigidBodyAngularVelocity(long physicsPtr, RigidBody rigidBody, Vector3d angularVelocity);
+
+    public static native AxisLock getRigidBodyLockTranslation(long physicsPtr, RigidBody rigidBody);
+    public static native void setRigidBodyLockTranslation(long physicsPtr, RigidBody rigidBody, AxisLock lockTranslation);
+
+    public static native AxisLock getRigidBodyLockRotation(long physicsPtr, RigidBody rigidBody);
+    public static native void setRigidBodyLockRotation(long physicsPtr, RigidBody rigidBody, AxisLock lockRotation);
+
+    public static native long[] getRigidBodyChildren(long physicsPtr, RigidBody rigidBody);
+    public static native void setRigidBodyChildren(long physicsPtr, RigidBody rigidBody, long[] children);
+
+    public static native void applyImpulse(long physicsPtr, RigidBody rigidBody, double x, double y, double z);
+    public static native void applyTorqueImpulse(long physicsPtr, RigidBody rigidBody, double x, double y, double z);
+}
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/scene/SceneLoadHandle.jvm.kt b/src/jvmMain/kotlin/com/dropbear/scene/SceneLoadHandle.jvm.kt
index 56bbcfc..a6bc25c 100644
--- a/src/jvmMain/kotlin/com/dropbear/scene/SceneLoadHandle.jvm.kt
+++ b/src/jvmMain/kotlin/com/dropbear/scene/SceneLoadHandle.jvm.kt
@@ -1,15 +1,21 @@
 package com.dropbear.scene
 
+import com.dropbear.DropbearEngine
 import com.dropbear.utils.Progress
 
-actual fun SceneLoadHandle.switchToSceneAsync(): SceneLoadHandle {
-    TODO("Not yet implemented")
+actual fun SceneLoadHandle.getSceneLoadHandleSceneName(id: Long): String {
+    return SceneLoadHandleNative.getSceneLoadHandleSceneName(DropbearEngine.native.sceneLoaderHandle, id)
+}
+
+actual fun SceneLoadHandle.switchToSceneAsync() {
+    return SceneLoadHandleNative.switchToSceneAsync(DropbearEngine.native.commandBufferHandle, this.id)
 }
 
 actual fun SceneLoadHandle.getSceneLoadProgress(): Progress {
-    TODO("Not yet implemented")
+    return SceneLoadHandleNative.getSceneLoadProgress(DropbearEngine.native.sceneLoaderHandle, this.id)
 }
 
 actual fun SceneLoadHandle.getSceneLoadStatus(): SceneLoadStatus {
-    TODO("Not yet implemented")
+    val result = SceneLoadHandleNative.getSceneLoadStatus(DropbearEngine.native.sceneLoaderHandle, this.id)
+    return SceneLoadStatus.entries[result]
 }
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/scene/SceneLoadHandleNative.java b/src/jvmMain/kotlin/com/dropbear/scene/SceneLoadHandleNative.java
new file mode 100644
index 0000000..28f72df
--- /dev/null
+++ b/src/jvmMain/kotlin/com/dropbear/scene/SceneLoadHandleNative.java
@@ -0,0 +1,15 @@
+package com.dropbear.scene;
+
+import com.dropbear.EucalyptusCoreLoader;
+import com.dropbear.utils.Progress;
+
+public class SceneLoadHandleNative {
+    static {
+        new EucalyptusCoreLoader().ensureLoaded();
+    }
+
+    public static native String getSceneLoadHandleSceneName(long sceneLoaderHandle, long sceneId);
+    public static native void switchToSceneAsync(long commandBufferPtr, long sceneId);
+    public static native Progress getSceneLoadProgress(long sceneLoaderHandle, long sceneId);
+    public static native int getSceneLoadStatus(long sceneLoaderHandle, long sceneId);
+}
diff --git a/src/jvmMain/kotlin/com/dropbear/scene/SceneManager.jvm.kt b/src/jvmMain/kotlin/com/dropbear/scene/SceneManager.jvm.kt
index 7524afa..6e3c201 100644
--- a/src/jvmMain/kotlin/com/dropbear/scene/SceneManager.jvm.kt
+++ b/src/jvmMain/kotlin/com/dropbear/scene/SceneManager.jvm.kt
@@ -1,15 +1,32 @@
 package com.dropbear.scene
 
+import com.dropbear.DropbearEngine
+
 actual fun SceneManager.loadSceneAsyncNative(sceneName: String): SceneLoadHandle? {
-    TODO("Not yet implemented")
+    val result = SceneManagerNative.loadSceneAsyncNative(
+        DropbearEngine.native.commandBufferHandle,
+        DropbearEngine.native.sceneLoaderHandle,
+        sceneName
+    )
+    return if (result != null) SceneLoadHandle(result) else null
 }
 
 actual fun SceneManager.loadSceneAsyncNative(
     sceneName: String,
-    loading_scene: String
+    loadingScene: String
 ): SceneLoadHandle? {
-    TODO("Not yet implemented")
+    val result = SceneManagerNative.loadSceneAsyncNative(
+        DropbearEngine.native.commandBufferHandle,
+        DropbearEngine.native.sceneLoaderHandle,
+        sceneName,
+        loadingScene
+    )
+    return if (result != null) SceneLoadHandle(result) else null
 }
 
 actual fun SceneManager.switchToSceneImmediateNative(sceneName: String) {
+    SceneManagerNative.switchToSceneImmediateNative(
+        DropbearEngine.native.commandBufferHandle,
+        sceneName
+    )
 }
\ No newline at end of file
diff --git a/src/jvmMain/kotlin/com/dropbear/scene/SceneManagerNative.java b/src/jvmMain/kotlin/com/dropbear/scene/SceneManagerNative.java
new file mode 100644
index 0000000..7788660
--- /dev/null
+++ b/src/jvmMain/kotlin/com/dropbear/scene/SceneManagerNative.java
@@ -0,0 +1,13 @@
+package com.dropbear.scene;
+
+import com.dropbear.EucalyptusCoreLoader;
+
+public class SceneManagerNative {
+    static {
+        new EucalyptusCoreLoader().ensureLoaded();
+    }
+
+    public static native Long loadSceneAsyncNative(long commandBufferPtr, long sceneManagerHandle, String sceneName);
+    public static native Long loadSceneAsyncNative(long commandBufferPtr, long sceneManagerHandle, String sceneName, String loadingScene);
+    public static native void switchToSceneImmediateNative(long commandBufferPtr, String sceneName);
+}
\ No newline at end of file
diff --git a/src/nativeMain/kotlin/com/dropbear/Camera.native.kt b/src/nativeMain/kotlin/com/dropbear/Camera.native.kt
deleted file mode 100644
index 3a451f1..0000000
--- a/src/nativeMain/kotlin/com/dropbear/Camera.native.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.dropbear
-
-import com.dropbear.math.Vector3D
-
-actual fun Camera.getCameraEye(entity: EntityId): Vector3D {
-    TODO("Not yet implemented")
-}
-
-actual fun Camera.setCameraEye(entity: EntityId, value: Vector3D) {
-}
-
-actual fun Camera.getCameraTarget(entity: EntityId): Vector3D {
-    TODO("Not yet implemented")
-}
-
-actual fun Camera.setCameraTarget(entity: EntityId, value: Vector3D) {
-}
-
-actual fun Camera.getCameraUp(entity: EntityId): Vector3D {
-    TODO("Not yet implemented")
-}
-
-actual fun Camera.setCameraUp(entity: EntityId, value: Vector3D) {
-}
-
-actual fun Camera.getCameraAspect(entity: EntityId): Double {
-    TODO("Not yet implemented")
-}
-
-actual fun Camera.getCameraFovY(entity: EntityId): Double {
-    TODO("Not yet implemented")
-}
-
-actual fun Camera.setCameraFovY(entity: EntityId, value: Double) {
-}
-
-actual fun Camera.getCameraZNear(entity: EntityId): Double {
-    TODO("Not yet implemented")
-}
-
-actual fun Camera.setCameraZNear(entity: EntityId, value: Double) {
-}
-
-actual fun Camera.getCameraZFar(entity: EntityId): Double {
-    TODO("Not yet implemented")
-}
-
-actual fun Camera.setCameraZFar(entity: EntityId, value: Double) {
-}
-
-actual fun Camera.getCameraYaw(entity: EntityId): Double {
-    TODO("Not yet implemented")
-}
-
-actual fun Camera.getCameraPitch(entity: EntityId): Double {
-    TODO("Not yet implemented")
-}
-
-actual fun Camera.setCameraYaw(entity: EntityId, value: Double) {
-}
-
-actual fun Camera.setCameraPitch(entity: EntityId, value: Double) {
-}
-
-actual fun Camera.getCameraSpeed(entity: EntityId): Double {
-    TODO("Not yet implemented")
-}
-
-actual fun Camera.setCameraSpeed(entity: EntityId, value: Double) {
-}
-
-actual fun Camera.getCameraSensitivity(entity: EntityId): Double {
-    TODO("Not yet implemented")
-}
-
-actual fun Camera.setCameraSensitivity(entity: EntityId, value: Double) {
-}
-
-actual fun cameraExistsForEntity(entity: EntityId): Boolean {
-    TODO("Not yet implemented")
-}
\ No newline at end of file
diff --git a/src/nativeMain/kotlin/com/dropbear/CustomProperties.native.kt b/src/nativeMain/kotlin/com/dropbear/CustomProperties.native.kt
deleted file mode 100644
index 8923627..0000000
--- a/src/nativeMain/kotlin/com/dropbear/CustomProperties.native.kt
+++ /dev/null
@@ -1,93 +0,0 @@
-package com.dropbear
-
-actual fun CustomProperties.getStringProperty(
-    entityHandle: Long,
-    label: String
-): String? {
-    TODO("Not yet implemented")
-}
-
-actual fun CustomProperties.getIntProperty(entityHandle: Long, label: String): Int? {
-    TODO("Not yet implemented")
-}
-
-actual fun CustomProperties.getLongProperty(
-    entityHandle: Long,
-    label: String
-): Long? {
-    TODO("Not yet implemented")
-}
-
-actual fun CustomProperties.getDoubleProperty(
-    entityHandle: Long,
-    label: String
-): Double? {
-    TODO("Not yet implemented")
-}
-
-actual fun CustomProperties.getFloatProperty(
-    entityHandle: Long,
-    label: String
-): Float? {
-    TODO("Not yet implemented")
-}
-
-actual fun CustomProperties.getBoolProperty(
-    entityHandle: Long,
-    label: String
-): Boolean? {
-    TODO("Not yet implemented")
-}
-
-actual fun CustomProperties.getVec3Property(
-    entityHandle: Long,
-    label: String
-): FloatArray? {
-    TODO("Not yet implemented")
-}
-
-actual fun CustomProperties.setStringProperty(
-    entityHandle: Long,
-    label: String,
-    value: String
-) {
-}
-
-actual fun CustomProperties.setIntProperty(
-    entityHandle: Long,
-    label: String,
-    value: Int
-) {
-}
-
-actual fun CustomProperties.setLongProperty(
-    entityHandle: Long,
-    label: String,
-    value: Long
-) {
-}
-
-actual fun CustomProperties.setFloatProperty(
-    entityHandle: Long,
-    label: String,
-    value: Double
-) {
-}
-
-actual fun CustomProperties.setBoolProperty(
-    entityHandle: Long,
-    label: String,
-    value: Boolean
-) {
-}
-
-actual fun CustomProperties.setVec3Property(
-    entityHandle: Long,
-    label: String,
-    value: FloatArray
-) {
-}
-
-actual fun customPropertiesExistsForEntity(entityId: EntityId): Boolean {
-    TODO("Not yet implemented")
-}
\ No newline at end of file
diff --git a/src/nativeMain/kotlin/com/dropbear/DropbearEngine.native.kt b/src/nativeMain/kotlin/com/dropbear/DropbearEngine.native.kt
index ed78c58..6562bca 100644
--- a/src/nativeMain/kotlin/com/dropbear/DropbearEngine.native.kt
+++ b/src/nativeMain/kotlin/com/dropbear/DropbearEngine.native.kt
@@ -1,10 +1,8 @@
 package com.dropbear
 
-actual fun getEntity(label: String): Long? {
-    TODO("Not yet implemented")
-}
+import com.dropbear.components.Camera
 
-actual fun getCamera(label: String): Camera? {
+actual fun getEntity(label: String): Long? {
     TODO("Not yet implemented")
 }
 
diff --git a/src/nativeMain/kotlin/com/dropbear/EntityTransform.native.kt b/src/nativeMain/kotlin/com/dropbear/EntityTransform.native.kt
deleted file mode 100644
index 4291a56..0000000
--- a/src/nativeMain/kotlin/com/dropbear/EntityTransform.native.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.dropbear
-
-import com.dropbear.math.Transform
-
-actual fun EntityTransform.getLocalTransform(entityId: EntityId): Transform {
-    TODO("Not yet implemented")
-}
-
-actual fun EntityTransform.setLocalTransform(
-    entityId: EntityId,
-    transform: Transform
-) {
-}
-
-actual fun EntityTransform.getWorldTransform(entityId: EntityId): Transform {
-    TODO("Not yet implemented")
-}
-
-actual fun EntityTransform.setWorldTransform(
-    entityId: EntityId,
-    transform: Transform
-) {
-}
-
-actual fun EntityTransform.propagateTransform(entityId: EntityId): Transform {
-    TODO("Not yet implemented")
-}
-
-actual fun entityTransformExistsForEntity(entityId: EntityId): Boolean {
-    TODO("Not yet implemented")
-}
\ No newline at end of file
diff --git a/src/nativeMain/kotlin/com/dropbear/MeshRenderer.native.kt b/src/nativeMain/kotlin/com/dropbear/MeshRenderer.native.kt
deleted file mode 100644
index b41d5dc..0000000
--- a/src/nativeMain/kotlin/com/dropbear/MeshRenderer.native.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.dropbear
-
-import com.dropbear.asset.ModelHandle
-import com.dropbear.asset.TextureHandle
-
-actual fun MeshRenderer.getModel(id: EntityId): ModelHandle? {
-    TODO("Not yet implemented")
-}
-
-actual fun MeshRenderer.setModel(id: EntityId, model: ModelHandle?) {
-}
-
-actual fun MeshRenderer.getAllTextureIds(id: EntityId): List<TextureHandle>? {
-    TODO("Not yet implemented")
-}
-
-actual fun MeshRenderer.getMaterialNames(id: EntityId): List<String> {
-    TODO("Not yet implemented")
-}
-
-actual fun MeshRenderer.setMaterialNames(id: EntityId, names: Array<String>) {
-}
-
-actual fun MeshRenderer.getTexture(id: EntityId, materialName: String): Long {
-    TODO("Not yet implemented")
-}
-
-actual fun MeshRenderer.setTextureOverride(
-    id: EntityId,
-    materialName: String,
-    textureHandle: Long
-) {
-}
-
-actual fun meshRendererExistsForEntity(entityId: EntityId): Boolean {
-    TODO("Not yet implemented")
-}
\ No newline at end of file
diff --git a/src/nativeMain/kotlin/com/dropbear/asset/AssetHandle.native.kt b/src/nativeMain/kotlin/com/dropbear/asset/AssetHandle.native.kt
index 983549e..819c8ba 100644
--- a/src/nativeMain/kotlin/com/dropbear/asset/AssetHandle.native.kt
+++ b/src/nativeMain/kotlin/com/dropbear/asset/AssetHandle.native.kt
@@ -1,9 +1,9 @@
 package com.dropbear.asset
 
-actual fun AssetHandle.asTextureHandle(): TextureHandle? {
+actual fun isModelHandle(id: Long): Boolean {
     TODO("Not yet implemented")
 }
 
-actual fun isModelHandle(id: Long): Boolean {
+actual fun isTextureHandle(id: Long): Boolean {
     TODO("Not yet implemented")
 }
\ No newline at end of file
diff --git a/src/nativeMain/kotlin/com/dropbear/components/Camera.native.kt b/src/nativeMain/kotlin/com/dropbear/components/Camera.native.kt
new file mode 100644
index 0000000..bcffc6e
--- /dev/null
+++ b/src/nativeMain/kotlin/com/dropbear/components/Camera.native.kt
@@ -0,0 +1,82 @@
+package com.dropbear.components
+
+import com.dropbear.EntityId
+import com.dropbear.math.Vector3d
+
+actual fun Camera.getCameraEye(entity: EntityId): Vector3d {
+    TODO("Not yet implemented")
+}
+
+actual fun Camera.setCameraEye(entity: EntityId, value: Vector3d) {
+}
+
+actual fun Camera.getCameraTarget(entity: EntityId): Vector3d {
+    TODO("Not yet implemented")
+}
+
+actual fun Camera.setCameraTarget(entity: EntityId, value: Vector3d) {
+}
+
+actual fun Camera.getCameraUp(entity: EntityId): Vector3d {
+    TODO("Not yet implemented")
+}
+
+actual fun Camera.setCameraUp(entity: EntityId, value: Vector3d) {
+}
+
+actual fun Camera.getCameraAspect(entity: EntityId): Double {
+    TODO("Not yet implemented")
+}
+
+actual fun Camera.getCameraFovY(entity: EntityId): Double {
+    TODO("Not yet implemented")
+}
+
+actual fun Camera.setCameraFovY(entity: EntityId, value: Double) {
+}
+
+actual fun Camera.getCameraZNear(entity: EntityId): Double {
+    TODO("Not yet implemented")
+}
+
+actual fun Camera.setCameraZNear(entity: EntityId, value: Double) {
+}
+
+actual fun Camera.getCameraZFar(entity: EntityId): Double {
+    TODO("Not yet implemented")
+}
+
+actual fun Camera.setCameraZFar(entity: EntityId, value: Double) {
+}
+
+actual fun Camera.getCameraYaw(entity: EntityId): Double {
+    TODO("Not yet implemented")
+}
+
+actual fun Camera.getCameraPitch(entity: EntityId): Double {
+    TODO("Not yet implemented")
+}
+
+actual fun Camera.setCameraYaw(entity: EntityId, value: Double) {
+}
+
+actual fun Camera.setCameraPitch(entity: EntityId, value: Double) {
+}
+
+actual fun Camera.getCameraSpeed(entity: EntityId): Double {
+    TODO("Not yet implemented")
+}
+
+actual fun Camera.setCameraSpeed(entity: EntityId, value: Double) {
+}
+
+actual fun Camera.getCameraSensitivity(entity: EntityId): Double {
+    TODO("Not yet implemented")
+}
+
+actual fun Camera.setCameraSensitivity(entity: EntityId, value: Double) {
+}
+
+actual fun cameraExistsForEntity(entity: EntityId): Boolean {
+    TODO("Not yet implemented")
+}
\ No newline at end of file
diff --git a/src/nativeMain/kotlin/com/dropbear/components/CustomProperties.native.kt b/src/nativeMain/kotlin/com/dropbear/components/CustomProperties.native.kt
new file mode 100644
index 0000000..70d6faa
--- /dev/null
+++ b/src/nativeMain/kotlin/com/dropbear/components/CustomProperties.native.kt
@@ -0,0 +1,96 @@
+package com.dropbear.components
+
+import com.dropbear.EntityId
+import com.dropbear.math.Vector3d
+
+actual fun CustomProperties.getStringProperty(
+    entityHandle: Long,
+    label: String
+): String? {
+    TODO("Not yet implemented")
+}
+
+actual fun CustomProperties.getIntProperty(entityHandle: Long, label: String): Int? {
+    TODO("Not yet implemented")
+}
+
+actual fun CustomProperties.getLongProperty(
+    entityHandle: Long,
+    label: String
+): Long? {
+    TODO("Not yet implemented")
+}
+
+actual fun CustomProperties.getDoubleProperty(
+    entityHandle: Long,
+    label: String
+): Double? {
+    TODO("Not yet implemented")
+}
+
+actual fun CustomProperties.getFloatProperty(
+    entityHandle: Long,
+    label: String
+): Float? {
+    TODO("Not yet implemented")
+}
+
+actual fun CustomProperties.getBoolProperty(
+    entityHandle: Long,
+    label: String
+): Boolean? {
+    TODO("Not yet implemented")
+}
+
+actual fun CustomProperties.getVec3Property(
+    entityHandle: Long,
+    label: String
+): Vector3d? {
+    TODO("Not yet implemented")
+}
+
+actual fun CustomProperties.setStringProperty(
+    entityHandle: Long,
+    label: String,
+    value: String
+) {
+}
+
+actual fun CustomProperties.setIntProperty(
+    entityHandle: Long,
+    label: String,
+    value: Int
+) {
+}
+
+actual fun CustomProperties.setLongProperty(
+    entityHandle: Long,
+    label: String,
+    value: Long
+) {
+}
+
+actual fun CustomProperties.setFloatProperty(
+    entityHandle: Long,
+    label: String,
+    value: Double
+) {
+}
+
+actual fun CustomProperties.setBoolProperty(
+    entityHandle: Long,
+    label: String,
+    value: Boolean
+) {
+}
+
+actual fun CustomProperties.setVec3Property(
+    entityHandle: Long,
+    label: String,
+    value: Vector3d
+) {
+}
+
+actual fun customPropertiesExistsForEntity(entityId: EntityId): Boolean {
+    TODO("Not yet implemented")
+}
\ No newline at end of file
diff --git a/src/nativeMain/kotlin/com/dropbear/components/EntityTransform.native.kt b/src/nativeMain/kotlin/com/dropbear/components/EntityTransform.native.kt
new file mode 100644
index 0000000..d455eb1
--- /dev/null
+++ b/src/nativeMain/kotlin/com/dropbear/components/EntityTransform.native.kt
@@ -0,0 +1,32 @@
+package com.dropbear.components
+
+import com.dropbear.EntityId
+import com.dropbear.math.Transform
+
+actual fun EntityTransform.getLocalTransform(entityId: EntityId): Transform {
+    TODO("Not yet implemented")
+}
+
+actual fun EntityTransform.setLocalTransform(
+    entityId: EntityId,
+    transform: Transform
+) {
+}
+
+actual fun EntityTransform.getWorldTransform(entityId: EntityId): Transform {
+    TODO("Not yet implemented")
+}
+
+actual fun EntityTransform.setWorldTransform(
+    entityId: EntityId,
+    transform: Transform
+) {
+}
+
+actual fun EntityTransform.propagateTransform(entityId: EntityId): Transform {
+    TODO("Not yet implemented")
+}
+
+actual fun entityTransformExistsForEntity(entityId: EntityId): Boolean {
+    TODO("Not yet implemented")
+}
\ No newline at end of file
diff --git a/src/nativeMain/kotlin/com/dropbear/components/MeshRenderer.native.kt b/src/nativeMain/kotlin/com/dropbear/components/MeshRenderer.native.kt
new file mode 100644
index 0000000..4803fb3
--- /dev/null
+++ b/src/nativeMain/kotlin/com/dropbear/components/MeshRenderer.native.kt
@@ -0,0 +1,31 @@
+package com.dropbear.components
+
+import com.dropbear.EntityId
+import com.dropbear.asset.ModelHandle
+import com.dropbear.asset.TextureHandle
+
+actual fun MeshRenderer.getModel(id: EntityId): ModelHandle? {
+    TODO("Not yet implemented")
+}
+
+actual fun MeshRenderer.setModel(id: EntityId, model: ModelHandle?) {
+}
+
+actual fun MeshRenderer.getAllTextureIds(id: EntityId): List<TextureHandle>? {
+    TODO("Not yet implemented")
+}
+
+actual fun MeshRenderer.getTexture(id: EntityId, materialName: String): Long {
+    TODO("Not yet implemented")
+}
+
+actual fun MeshRenderer.setTextureOverride(
+    id: EntityId,
+    materialName: String,
+    textureHandle: Long
+) {
+}
+
+actual fun meshRendererExistsForEntity(entityId: EntityId): Boolean {
+    TODO("Not yet implemented")
+}
\ No newline at end of file
diff --git a/src/nativeMain/kotlin/com/dropbear/input/Gamepad.native.kt b/src/nativeMain/kotlin/com/dropbear/input/Gamepad.native.kt
index ea1c67c..262b6ac 100644
--- a/src/nativeMain/kotlin/com/dropbear/input/Gamepad.native.kt
+++ b/src/nativeMain/kotlin/com/dropbear/input/Gamepad.native.kt
@@ -1,8 +1,19 @@
 package com.dropbear.input
 
+import com.dropbear.math.Vector2d
+
 actual fun Gamepad.isGamepadButtonPressed(
     id: Long,
     button: GamepadButton
 ): Boolean {
     TODO("Not yet implemented")
-}
\ No newline at end of file
+}
+
+actual fun Gamepad.getLeftStickPosition(id: Long): Vector2d {
+    TODO("Not yet implemented")
+}
+
+actual fun Gamepad.getRightStickPosition(id: Long): Vector2d {
+    TODO("Not yet implemented")
+}
+
diff --git a/src/nativeMain/kotlin/com/dropbear/input/InputState.native.kt b/src/nativeMain/kotlin/com/dropbear/input/InputState.native.kt
index d41379b..2844b4d 100644
--- a/src/nativeMain/kotlin/com/dropbear/input/InputState.native.kt
+++ b/src/nativeMain/kotlin/com/dropbear/input/InputState.native.kt
@@ -1,6 +1,6 @@
 package com.dropbear.input
 
-import com.dropbear.math.Vector2D
+import com.dropbear.math.Vector2d
 
 actual class InputState actual constructor() {
     actual fun printInputState() {
@@ -10,7 +10,7 @@ actual class InputState actual constructor() {
         TODO("Not yet implemented")
     }
 
-    actual fun getMousePosition(): Vector2D {
+    actual fun getMousePosition(): Vector2d {
         TODO("Not yet implemented")
     }
 
@@ -18,7 +18,7 @@ actual class InputState actual constructor() {
         TODO("Not yet implemented")
     }
 
-    actual fun getMouseDelta(): Vector2D {
+    actual fun getMouseDelta(): Vector2d {
         TODO("Not yet implemented")
     }
 
@@ -29,7 +29,7 @@ actual class InputState actual constructor() {
     actual fun setCursorLocked(locked: Boolean) {
     }
 
-    actual fun getLastMousePos(): Vector2D {
+    actual fun getLastMousePos(): Vector2d {
         TODO("Not yet implemented")
     }
 
diff --git a/src/nativeMain/kotlin/com/dropbear/physics/Collider.native.kt b/src/nativeMain/kotlin/com/dropbear/physics/Collider.native.kt
index 5de9593..0e82eef 100644
--- a/src/nativeMain/kotlin/com/dropbear/physics/Collider.native.kt
+++ b/src/nativeMain/kotlin/com/dropbear/physics/Collider.native.kt
@@ -1,6 +1,6 @@
 package com.dropbear.physics
 
-import com.dropbear.math.Vector3D
+import com.dropbear.math.Vector3d
 
 actual fun Collider.getColliderShape(collider: Collider): ColliderShape {
     TODO("Not yet implemented")
@@ -48,23 +48,23 @@ actual fun Collider.setColliderIsSensor(
 ) {
 }
 
-actual fun Collider.getColliderTranslation(collider: Collider): Vector3D {
+actual fun Collider.getColliderTranslation(collider: Collider): Vector3d {
     TODO("Not yet implemented")
 }
 
 actual fun Collider.setColliderTranslation(
     collider: Collider,
-    translation: Vector3D
+    translation: Vector3d
 ) {
 }
 
-actual fun Collider.getColliderRotation(collider: Collider): Vector3D {
+actual fun Collider.getColliderRotation(collider: Collider): Vector3d {
     TODO("Not yet implemented")
 }
 
 actual fun Collider.setColliderRotation(
     collider: Collider,
-    rotation: Vector3D
+    rotation: Vector3d
 ) {
 }
 
@@ -77,4 +77,5 @@ actual fun Collider.setColliderMass(collider: Collider, mass: Double) {
 
 actual fun Collider.getColliderDensity(collider: Collider): Double {
     TODO("Not yet implemented")
-}
\ No newline at end of file
+}
+
diff --git a/src/nativeMain/kotlin/com/dropbear/physics/RigidBody.native.kt b/src/nativeMain/kotlin/com/dropbear/physics/RigidBody.native.kt
index 93d12d1..8ae6c95 100644
--- a/src/nativeMain/kotlin/com/dropbear/physics/RigidBody.native.kt
+++ b/src/nativeMain/kotlin/com/dropbear/physics/RigidBody.native.kt
@@ -1,7 +1,7 @@
 package com.dropbear.physics
 
 import com.dropbear.EntityId
-import com.dropbear.math.Vector3D
+import com.dropbear.math.Vector3d
 
 actual fun RigidBody.setRigidbodyMode(
     rigidBody: RigidBody,
@@ -43,7 +43,7 @@ actual fun RigidBody.setRigidbodyCcdEnabled(
 ) {
 }
 
-actual fun RigidBody.getRigidbodyLinearVelocity(rigidBody: RigidBody): Vector3D {
+actual fun RigidBody.getRigidbodyLinearVelocity(rigidBody: RigidBody): Vector3d {
     TODO("Not yet implemented")
 }
 
@@ -55,17 +55,17 @@ actual fun RigidBody.setRigidbodyLinearDamping(
 
 actual fun RigidBody.setRigidbodyLinearVelocity(
     rigidBody: RigidBody,
-    linearVelocity: Vector3D
+    linearVelocity: Vector3d
 ) {
 }
 
-actual fun RigidBody.getRigidbodyAngularVelocity(rigidBody: RigidBody): Vector3D {
+actual fun RigidBody.getRigidbodyAngularVelocity(rigidBody: RigidBody): Vector3d {
     TODO("Not yet implemented")
 }
 
 actual fun RigidBody.setRigidbodyAngularVelocity(
     rigidBody: RigidBody,
-    angularVelocity: Vector3D
+    angularVelocity: Vector3d
 ) {
 }
 
diff --git a/src/nativeMain/kotlin/com/dropbear/scene/SceneLoadHandle.native.kt b/src/nativeMain/kotlin/com/dropbear/scene/SceneLoadHandle.native.kt
index 56bbcfc..6ca7428 100644
--- a/src/nativeMain/kotlin/com/dropbear/scene/SceneLoadHandle.native.kt
+++ b/src/nativeMain/kotlin/com/dropbear/scene/SceneLoadHandle.native.kt
@@ -2,7 +2,7 @@ package com.dropbear.scene
 
 import com.dropbear.utils.Progress
 
-actual fun SceneLoadHandle.switchToSceneAsync(): SceneLoadHandle {
+actual fun SceneLoadHandle.switchToSceneAsync() {
     TODO("Not yet implemented")
 }
 
@@ -12,4 +12,8 @@ actual fun SceneLoadHandle.getSceneLoadProgress(): Progress {
 
 actual fun SceneLoadHandle.getSceneLoadStatus(): SceneLoadStatus {
     TODO("Not yet implemented")
+}
+
+actual fun SceneLoadHandle.getSceneLoadHandleSceneName(id: Long): String {
+    TODO("Not yet implemented")
 }
\ No newline at end of file
diff --git a/src/nativeMain/kotlin/com/dropbear/scene/SceneManager.native.kt b/src/nativeMain/kotlin/com/dropbear/scene/SceneManager.native.kt
index 7524afa..8217884 100644
--- a/src/nativeMain/kotlin/com/dropbear/scene/SceneManager.native.kt
+++ b/src/nativeMain/kotlin/com/dropbear/scene/SceneManager.native.kt
@@ -6,7 +6,7 @@ actual fun SceneManager.loadSceneAsyncNative(sceneName: String): SceneLoadHandle
 
 actual fun SceneManager.loadSceneAsyncNative(
     sceneName: String,
-    loading_scene: String
+    loadingScene: String
 ): SceneLoadHandle? {
     TODO("Not yet implemented")
 }