diff --git a/Assets/StraightFour/Entity/Character/Scripts/CharacterEntity.cs b/Assets/StraightFour/Entity/Character/Scripts/CharacterEntity.cs
index d8d8251..e676a43 100644
--- a/Assets/StraightFour/Entity/Character/Scripts/CharacterEntity.cs
+++ b/Assets/StraightFour/Entity/Character/Scripts/CharacterEntity.cs
@@ -72,6 +72,143 @@ public override string entityTag {
[Tooltip("Whether or not to fix the height if below ground.")]
public bool fixHeight = true;
+ ///
+ /// Set the character GameObject at runtime.
+ ///
+ /// The new character GameObject to use.
+ /// Whether or not to synchronize the change.
+ /// Whether or not the setting was successful.
+ public bool SetCharacterGO(GameObject newCharacterGO, bool synchronize = true)
+ {
+ if (newCharacterGO == null)
+ {
+ LogSystem.LogError("[CharacterEntity->SetCharacterGO] Character GameObject cannot be null.");
+ return false;
+ }
+
+ // Store old character GameObject
+ GameObject oldCharacterGO = characterGO;
+
+ // Set the new character GameObject
+ characterGO = newCharacterGO;
+ characterGO.SetActive(true);
+ characterGO.transform.SetParent(transform);
+ characterGO.transform.localPosition = characterObjectOffset;
+ characterGO.transform.localRotation = characterObjectRotation;
+
+ // Update meshes for the new character GameObject
+ List ms = new List();
+ foreach (MeshFilter filt in characterGO.GetComponentsInChildren())
+ {
+ ms.Add(filt.sharedMesh);
+ }
+ SetRenderers(ms.ToArray());
+
+ // Calculate new bounds
+ Bounds bounds = new Bounds(Vector3.zero, Vector3.zero);
+ foreach (Mesh m in meshes)
+ {
+ m.RecalculateBounds();
+ bounds.Encapsulate(m.bounds);
+ }
+ originalMeshSize = bounds.size;
+
+ // Clean up old character GameObject
+ if (oldCharacterGO != null)
+ {
+ DestroyImmediate(oldCharacterGO);
+ }
+
+ if (synchronize && synchronizer != null)
+ {
+ // Note: Synchronization logic would go here if needed
+ }
+
+ return true;
+ }
+
+ ///
+ /// Set the character object offset at runtime.
+ ///
+ /// The new offset to apply.
+ /// Whether or not to synchronize the change.
+ /// Whether or not the setting was successful.
+ public bool SetCharacterObjectOffset(Vector3 newOffset, bool synchronize = true)
+ {
+ if (characterGO == null)
+ {
+ LogSystem.LogError("[CharacterEntity->SetCharacterObjectOffset] No character GameObject.");
+ return false;
+ }
+
+ characterObjectOffset = newOffset;
+ characterGO.transform.localPosition = characterObjectOffset;
+
+ if (synchronize && synchronizer != null)
+ {
+ // Note: Synchronization logic would go here if needed
+ }
+
+ return true;
+ }
+
+ ///
+ /// Set the character object rotation at runtime.
+ ///
+ /// The new rotation to apply.
+ /// Whether or not to synchronize the change.
+ /// Whether or not the setting was successful.
+ public bool SetCharacterObjectRotation(Quaternion newRotation, bool synchronize = true)
+ {
+ if (characterGO == null)
+ {
+ LogSystem.LogError("[CharacterEntity->SetCharacterObjectRotation] No character GameObject.");
+ return false;
+ }
+
+ characterObjectRotation = newRotation;
+ characterGO.transform.localRotation = characterObjectRotation;
+
+ if (synchronize && synchronizer != null)
+ {
+ // Note: Synchronization logic would go here if needed
+ }
+
+ return true;
+ }
+
+ ///
+ /// Set the character label offset at runtime.
+ ///
+ /// The new offset to apply.
+ /// Whether or not to synchronize the change.
+ /// Whether or not the setting was successful.
+ public bool SetCharacterLabelOffset(Vector3 newOffset, bool synchronize = true)
+ {
+ if (characterGO == null)
+ {
+ LogSystem.LogError("[CharacterEntity->SetCharacterLabelOffset] No character GameObject.");
+ return false;
+ }
+
+ characterLabelOffset = newOffset;
+
+ // Find the character label and update its position
+ TextMeshProUGUI[] labels = characterGO.GetComponentsInChildren();
+ foreach (TextMeshProUGUI label in labels)
+ {
+ label.transform.localPosition = characterLabelOffset;
+ break; // Assume there's only one label per character
+ }
+
+ if (synchronize && synchronizer != null)
+ {
+ // Note: Synchronization logic would go here if needed
+ }
+
+ return true;
+ }
+
///
/// Minimum height to allow character entity to be at.
///
@@ -89,6 +226,15 @@ public override string entityTag {
///
private GameObject characterGO;
+ ///
+ /// Get the character GameObject.
+ ///
+ /// The current character GameObject.
+ public GameObject GetCharacterGO()
+ {
+ return characterGO;
+ }
+
///
/// Meshes on the character model.
///
diff --git a/Assets/StraightFour/Testing/EntityTests/CharacterEntityRuntimeDemo.cs b/Assets/StraightFour/Testing/EntityTests/CharacterEntityRuntimeDemo.cs
new file mode 100644
index 0000000..3181322
--- /dev/null
+++ b/Assets/StraightFour/Testing/EntityTests/CharacterEntityRuntimeDemo.cs
@@ -0,0 +1,110 @@
+// Copyright (c) 2019-2025 Five Squared Interactive. All rights reserved.
+
+using UnityEngine;
+using FiveSQD.StraightFour.Entity;
+using System;
+
+///
+/// Example script demonstrating the new runtime APIs for CharacterEntity
+///
+public class CharacterEntityRuntimeDemo : MonoBehaviour
+{
+ [Header("Character Entity Runtime API Demo")]
+ public CharacterEntity characterEntity;
+
+ [Header("Test Values")]
+ public Vector3 newOffset = new Vector3(0, 1, 0);
+ public Vector3 newRotationEuler = new Vector3(0, 45, 0);
+ public Vector3 newLabelOffset = new Vector3(0, 2, 0);
+ public GameObject newCharacterPrefab;
+
+ [Header("Controls")]
+ [Space]
+ public bool updateOffset;
+ public bool updateRotation;
+ public bool updateLabelOffset;
+ public bool updateCharacterGO;
+
+ void Update()
+ {
+ if (characterEntity == null) return;
+
+ // Update character object offset
+ if (updateOffset)
+ {
+ updateOffset = false;
+ bool success = characterEntity.SetCharacterObjectOffset(newOffset);
+ Debug.Log($"Set character object offset to {newOffset}: {(success ? "Success" : "Failed")}");
+ }
+
+ // Update character object rotation
+ if (updateRotation)
+ {
+ updateRotation = false;
+ Quaternion newRotation = Quaternion.Euler(newRotationEuler);
+ bool success = characterEntity.SetCharacterObjectRotation(newRotation);
+ Debug.Log($"Set character object rotation to {newRotationEuler}: {(success ? "Success" : "Failed")}");
+ }
+
+ // Update character label offset
+ if (updateLabelOffset)
+ {
+ updateLabelOffset = false;
+ bool success = characterEntity.SetCharacterLabelOffset(newLabelOffset);
+ Debug.Log($"Set character label offset to {newLabelOffset}: {(success ? "Success" : "Failed")}");
+ }
+
+ // Update character GameObject
+ if (updateCharacterGO && newCharacterPrefab != null)
+ {
+ updateCharacterGO = false;
+ bool success = characterEntity.SetCharacterGO(newCharacterPrefab);
+ Debug.Log($"Set character GameObject: {(success ? "Success" : "Failed")}");
+ }
+ }
+
+ [ContextMenu("Demo - Update All Properties")]
+ public void DemoUpdateAllProperties()
+ {
+ if (characterEntity == null)
+ {
+ Debug.LogError("No CharacterEntity assigned!");
+ return;
+ }
+
+ // Get current values
+ Vector3 currentOffset = characterEntity.characterObjectOffset;
+ Quaternion currentRotation = characterEntity.characterObjectRotation;
+ Vector3 currentLabelOffset = characterEntity.characterLabelOffset;
+ GameObject currentGO = characterEntity.GetCharacterGO();
+
+ Debug.Log("=== CharacterEntity Runtime API Demo ===");
+ Debug.Log($"Current Offset: {currentOffset}");
+ Debug.Log($"Current Rotation: {currentRotation.eulerAngles}");
+ Debug.Log($"Current Label Offset: {currentLabelOffset}");
+ Debug.Log($"Current GameObject: {(currentGO != null ? currentGO.name : "null")}");
+
+ // Update offset
+ Vector3 testOffset = currentOffset + Vector3.up;
+ if (characterEntity.SetCharacterObjectOffset(testOffset))
+ {
+ Debug.Log($"✓ Successfully updated offset to {testOffset}");
+ }
+
+ // Update rotation
+ Quaternion testRotation = currentRotation * Quaternion.Euler(0, 45, 0);
+ if (characterEntity.SetCharacterObjectRotation(testRotation))
+ {
+ Debug.Log($"✓ Successfully updated rotation to {testRotation.eulerAngles}");
+ }
+
+ // Update label offset
+ Vector3 testLabelOffset = currentLabelOffset + Vector3.forward;
+ if (characterEntity.SetCharacterLabelOffset(testLabelOffset))
+ {
+ Debug.Log($"✓ Successfully updated label offset to {testLabelOffset}");
+ }
+
+ Debug.Log("=== Demo Complete ===");
+ }
+}
\ No newline at end of file
diff --git a/Assets/StraightFour/Testing/EntityTests/CharacterEntityRuntimeDemo.cs.meta b/Assets/StraightFour/Testing/EntityTests/CharacterEntityRuntimeDemo.cs.meta
new file mode 100644
index 0000000..1f7aa00
--- /dev/null
+++ b/Assets/StraightFour/Testing/EntityTests/CharacterEntityRuntimeDemo.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
\ No newline at end of file
diff --git a/Assets/StraightFour/Testing/EntityTests/CharacterEntityRuntimeTests.cs b/Assets/StraightFour/Testing/EntityTests/CharacterEntityRuntimeTests.cs
new file mode 100644
index 0000000..fd3b9ba
--- /dev/null
+++ b/Assets/StraightFour/Testing/EntityTests/CharacterEntityRuntimeTests.cs
@@ -0,0 +1,206 @@
+// Copyright (c) 2019-2025 Five Squared Interactive. All rights reserved.
+
+using System.Collections;
+using NUnit.Framework;
+using UnityEngine;
+using UnityEngine.TestTools;
+using FiveSQD.StraightFour.Entity;
+using System;
+using FiveSQD.StraightFour;
+using FiveSQD.StraightFour.Synchronization;
+using UnityEditor;
+using TMPro;
+
+public class CharacterEntityRuntimeTests
+{
+ [UnityTest]
+ public IEnumerator CharacterEntityRuntimeTests_SetCharacterObjectOffset()
+ {
+ // Initialize World Engine and Load World.
+ GameObject WEGO = new GameObject();
+ StraightFour we = WEGO.AddComponent();
+ we.characterControllerPrefab = AssetDatabase.LoadAssetAtPath("Assets/StraightFour/Entity/Character/Prefabs/UserAvatar.prefab");
+ we.characterControllerLabelPrefab = AssetDatabase.LoadAssetAtPath("Assets/StraightFour/Entity/Character/Prefabs/CharacterPrefabLabel.prefab");
+ we.skyMaterial = AssetDatabase.LoadAssetAtPath("Assets/StraightFour/Environment/Materials/skybox.mat");
+ yield return null;
+ StraightFour.LoadWorld("test");
+
+ // Create character entity
+ GameObject go = new GameObject();
+ CharacterEntity character = go.AddComponent();
+ Guid entityID = Guid.NewGuid();
+
+ Vector3 initialOffset = new Vector3(1, 2, 3);
+ character.Initialize(entityID, null, initialOffset, Quaternion.identity, Vector3.zero);
+
+ // Test getting initial offset
+ Assert.AreEqual(initialOffset, character.characterObjectOffset);
+
+ // Test setting new offset
+ Vector3 newOffset = new Vector3(4, 5, 6);
+ bool result = character.SetCharacterObjectOffset(newOffset);
+ Assert.IsTrue(result);
+ Assert.AreEqual(newOffset, character.characterObjectOffset);
+
+ // Verify the actual GameObject transform was updated
+ GameObject characterGO = character.GetCharacterGO();
+ Assert.IsNotNull(characterGO);
+ Assert.AreEqual(newOffset, characterGO.transform.localPosition);
+
+ // Clean up
+ character.Delete();
+ yield return null;
+ }
+
+ [UnityTest]
+ public IEnumerator CharacterEntityRuntimeTests_SetCharacterObjectRotation()
+ {
+ // Initialize World Engine and Load World.
+ GameObject WEGO = new GameObject();
+ StraightFour we = WEGO.AddComponent();
+ we.characterControllerPrefab = AssetDatabase.LoadAssetAtPath("Assets/StraightFour/Entity/Character/Prefabs/UserAvatar.prefab");
+ we.characterControllerLabelPrefab = AssetDatabase.LoadAssetAtPath("Assets/StraightFour/Entity/Character/Prefabs/CharacterPrefabLabel.prefab");
+ we.skyMaterial = AssetDatabase.LoadAssetAtPath("Assets/StraightFour/Environment/Materials/skybox.mat");
+ yield return null;
+ StraightFour.LoadWorld("test");
+
+ // Create character entity
+ GameObject go = new GameObject();
+ CharacterEntity character = go.AddComponent();
+ Guid entityID = Guid.NewGuid();
+
+ Quaternion initialRotation = Quaternion.Euler(45, 90, 180);
+ character.Initialize(entityID, null, Vector3.zero, initialRotation, Vector3.zero);
+
+ // Test getting initial rotation
+ Assert.AreEqual(initialRotation, character.characterObjectRotation);
+
+ // Test setting new rotation
+ Quaternion newRotation = Quaternion.Euler(30, 60, 90);
+ bool result = character.SetCharacterObjectRotation(newRotation);
+ Assert.IsTrue(result);
+ Assert.AreEqual(newRotation, character.characterObjectRotation);
+
+ // Verify the actual GameObject transform was updated
+ GameObject characterGO = character.GetCharacterGO();
+ Assert.IsNotNull(characterGO);
+ Assert.AreEqual(newRotation, characterGO.transform.localRotation);
+
+ // Clean up
+ character.Delete();
+ yield return null;
+ }
+
+ [UnityTest]
+ public IEnumerator CharacterEntityRuntimeTests_SetCharacterLabelOffset()
+ {
+ // Initialize World Engine and Load World.
+ GameObject WEGO = new GameObject();
+ StraightFour we = WEGO.AddComponent();
+ we.characterControllerPrefab = AssetDatabase.LoadAssetAtPath("Assets/StraightFour/Entity/Character/Prefabs/UserAvatar.prefab");
+ we.characterControllerLabelPrefab = AssetDatabase.LoadAssetAtPath("Assets/StraightFour/Entity/Character/Prefabs/CharacterPrefabLabel.prefab");
+ we.skyMaterial = AssetDatabase.LoadAssetAtPath("Assets/StraightFour/Environment/Materials/skybox.mat");
+ yield return null;
+ StraightFour.LoadWorld("test");
+
+ // Create character entity
+ GameObject go = new GameObject();
+ CharacterEntity character = go.AddComponent();
+ Guid entityID = Guid.NewGuid();
+
+ Vector3 initialLabelOffset = new Vector3(0, 2, 0);
+ character.Initialize(entityID, null, Vector3.zero, Quaternion.identity, initialLabelOffset);
+
+ // Test getting initial label offset
+ Assert.AreEqual(initialLabelOffset, character.characterLabelOffset);
+
+ // Test setting new label offset
+ Vector3 newLabelOffset = new Vector3(1, 3, 1);
+ bool result = character.SetCharacterLabelOffset(newLabelOffset);
+ Assert.IsTrue(result);
+ Assert.AreEqual(newLabelOffset, character.characterLabelOffset);
+
+ // Verify the actual label transform was updated
+ GameObject characterGO = character.GetCharacterGO();
+ Assert.IsNotNull(characterGO);
+ TextMeshProUGUI[] labels = characterGO.GetComponentsInChildren();
+ if (labels.Length > 0)
+ {
+ Assert.AreEqual(newLabelOffset, labels[0].transform.localPosition);
+ }
+
+ // Clean up
+ character.Delete();
+ yield return null;
+ }
+
+ [UnityTest]
+ public IEnumerator CharacterEntityRuntimeTests_SetCharacterGO()
+ {
+ // Initialize World Engine and Load World.
+ GameObject WEGO = new GameObject();
+ StraightFour we = WEGO.AddComponent();
+ we.characterControllerPrefab = AssetDatabase.LoadAssetAtPath("Assets/StraightFour/Entity/Character/Prefabs/UserAvatar.prefab");
+ we.characterControllerLabelPrefab = AssetDatabase.LoadAssetAtPath("Assets/StraightFour/Entity/Character/Prefabs/CharacterPrefabLabel.prefab");
+ we.skyMaterial = AssetDatabase.LoadAssetAtPath("Assets/StraightFour/Environment/Materials/skybox.mat");
+ yield return null;
+ StraightFour.LoadWorld("test");
+
+ // Create character entity
+ GameObject go = new GameObject();
+ CharacterEntity character = go.AddComponent();
+ Guid entityID = Guid.NewGuid();
+
+ character.Initialize(entityID, null, Vector3.zero, Quaternion.identity, Vector3.zero);
+
+ // Get initial character GameObject
+ GameObject initialCharacterGO = character.GetCharacterGO();
+ Assert.IsNotNull(initialCharacterGO);
+
+ // Create a new character GameObject (simple cube for testing)
+ GameObject newCharacterGO = GameObject.CreatePrimitive(PrimitiveType.Cube);
+
+ // Test setting new character GameObject
+ bool result = character.SetCharacterGO(newCharacterGO);
+ Assert.IsTrue(result);
+
+ // Verify the character GameObject was updated
+ GameObject currentCharacterGO = character.GetCharacterGO();
+ Assert.AreEqual(newCharacterGO, currentCharacterGO);
+ Assert.AreEqual(character.transform, currentCharacterGO.transform.parent);
+
+ // Test error handling with null GameObject
+ bool nullResult = character.SetCharacterGO(null);
+ Assert.IsFalse(nullResult);
+
+ // Clean up
+ character.Delete();
+ yield return null;
+ }
+
+ [UnityTest]
+ public IEnumerator CharacterEntityRuntimeTests_ErrorHandling()
+ {
+ // Test error handling when character is not properly initialized
+ GameObject go = new GameObject();
+ CharacterEntity character = go.AddComponent();
+
+ // These should all fail gracefully since no characterGO exists
+ bool offsetResult = character.SetCharacterObjectOffset(Vector3.one);
+ Assert.IsFalse(offsetResult);
+
+ bool rotationResult = character.SetCharacterObjectRotation(Quaternion.identity);
+ Assert.IsFalse(rotationResult);
+
+ bool labelOffsetResult = character.SetCharacterLabelOffset(Vector3.one);
+ Assert.IsFalse(labelOffsetResult);
+
+ // GetCharacterGO should return null
+ GameObject characterGO = character.GetCharacterGO();
+ Assert.IsNull(characterGO);
+
+ // Clean up
+ character.Delete();
+ yield return null;
+ }
+}
\ No newline at end of file
diff --git a/Assets/StraightFour/Testing/EntityTests/CharacterEntityRuntimeTests.cs.meta b/Assets/StraightFour/Testing/EntityTests/CharacterEntityRuntimeTests.cs.meta
new file mode 100644
index 0000000..1327db8
--- /dev/null
+++ b/Assets/StraightFour/Testing/EntityTests/CharacterEntityRuntimeTests.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7e8a9b0c1d2f3e4a5b6c7d8e9f0a1b2c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
\ No newline at end of file
diff --git a/Assets/StraightFour/Testing/EntityTests/CharacterEntity_RuntimeAPI_Documentation.md b/Assets/StraightFour/Testing/EntityTests/CharacterEntity_RuntimeAPI_Documentation.md
new file mode 100644
index 0000000..e8501e5
--- /dev/null
+++ b/Assets/StraightFour/Testing/EntityTests/CharacterEntity_RuntimeAPI_Documentation.md
@@ -0,0 +1,189 @@
+# CharacterEntity Runtime API Documentation
+
+This document describes the new runtime APIs added to the `CharacterEntity` class that allow dynamic updates to character properties during gameplay.
+
+## Overview
+
+Previously, the properties `characterGO`, `characterObjectOffset`, `characterObjectRotation`, and `characterLabelOffset` could only be set during entity initialization. The new runtime APIs allow these properties to be modified at any time during execution, enabling dynamic character management.
+
+## New APIs
+
+### 1. SetCharacterGO(GameObject newCharacterGO, bool synchronize = true)
+
+**Purpose**: Replace the character GameObject at runtime with a new one.
+
+**Parameters**:
+- `newCharacterGO`: The new character GameObject to use (cannot be null)
+- `synchronize`: Whether to synchronize the change (default: true)
+
+**Returns**: `bool` - Whether the operation was successful
+
+**Example**:
+```csharp
+GameObject newCharacter = Resources.Load("NewCharacterPrefab");
+bool success = characterEntity.SetCharacterGO(newCharacter);
+if (success)
+{
+ Debug.Log("Character GameObject updated successfully!");
+}
+```
+
+**Notes**:
+- Automatically updates mesh renderers and bounds calculations
+- Cleans up the old character GameObject
+- Preserves current offset and rotation settings
+
+### 2. GetCharacterGO()
+
+**Purpose**: Get the current character GameObject.
+
+**Returns**: `GameObject` - The current character GameObject (can be null)
+
+**Example**:
+```csharp
+GameObject currentCharacter = characterEntity.GetCharacterGO();
+if (currentCharacter != null)
+{
+ Debug.Log($"Current character: {currentCharacter.name}");
+}
+```
+
+### 3. SetCharacterObjectOffset(Vector3 newOffset, bool synchronize = true)
+
+**Purpose**: Update the character object's position offset at runtime.
+
+**Parameters**:
+- `newOffset`: The new position offset to apply
+- `synchronize`: Whether to synchronize the change (default: true)
+
+**Returns**: `bool` - Whether the operation was successful
+
+**Example**:
+```csharp
+// Move character slightly up
+Vector3 newOffset = new Vector3(0, 0.5f, 0);
+bool success = characterEntity.SetCharacterObjectOffset(newOffset);
+```
+
+**Notes**:
+- Immediately updates the character GameObject's local position
+- Updates the internal `characterObjectOffset` property
+
+### 4. SetCharacterObjectRotation(Quaternion newRotation, bool synchronize = true)
+
+**Purpose**: Update the character object's rotation at runtime.
+
+**Parameters**:
+- `newRotation`: The new rotation to apply
+- `synchronize`: Whether to synchronize the change (default: true)
+
+**Returns**: `bool` - Whether the operation was successful
+
+**Example**:
+```csharp
+// Rotate character 45 degrees around Y axis
+Quaternion newRotation = Quaternion.Euler(0, 45, 0);
+bool success = characterEntity.SetCharacterObjectRotation(newRotation);
+```
+
+**Notes**:
+- Immediately updates the character GameObject's local rotation
+- Updates the internal `characterObjectRotation` property
+
+### 5. SetCharacterLabelOffset(Vector3 newOffset, bool synchronize = true)
+
+**Purpose**: Update the character label's position offset at runtime.
+
+**Parameters**:
+- `newOffset`: The new label position offset to apply
+- `synchronize`: Whether to synchronize the change (default: true)
+
+**Returns**: `bool` - Whether the operation was successful
+
+**Example**:
+```csharp
+// Move label higher above character
+Vector3 newLabelOffset = new Vector3(0, 2.5f, 0);
+bool success = characterEntity.SetCharacterLabelOffset(newLabelOffset);
+```
+
+**Notes**:
+- Immediately updates the character label's local position
+- Updates the internal `characterLabelOffset` property
+- Finds TextMeshProUGUI components in character hierarchy
+
+## Error Handling
+
+All setter methods include proper error handling:
+
+- Return `false` if the operation fails
+- Log appropriate error messages to the console
+- Check for null character GameObject before operations
+- Validate input parameters
+
+**Common Error Cases**:
+- Calling methods before character is properly initialized
+- Passing null GameObject to `SetCharacterGO()`
+- Character GameObject has been destroyed
+
+## Backward Compatibility
+
+These new APIs are fully backward compatible:
+
+- Existing code continues to work unchanged
+- Original initialization methods remain functional
+- No breaking changes to existing interfaces
+- Properties maintain their original getter behavior
+
+## Usage Examples
+
+### Dynamic Character Customization
+```csharp
+public class CharacterCustomizer : MonoBehaviour
+{
+ public CharacterEntity character;
+ public GameObject[] characterVariants;
+
+ public void SwitchCharacterVariant(int index)
+ {
+ if (index < characterVariants.Length)
+ {
+ character.SetCharacterGO(characterVariants[index]);
+ }
+ }
+
+ public void AdjustCharacterHeight(float heightOffset)
+ {
+ Vector3 currentOffset = character.characterObjectOffset;
+ currentOffset.y = heightOffset;
+ character.SetCharacterObjectOffset(currentOffset);
+ }
+}
+```
+
+### Animation-Driven Updates
+```csharp
+public class CharacterAnimationController : MonoBehaviour
+{
+ public CharacterEntity character;
+
+ void Update()
+ {
+ // Gradually rotate character
+ Quaternion currentRotation = character.characterObjectRotation;
+ Quaternion newRotation = currentRotation * Quaternion.Euler(0, Time.deltaTime * 90, 0);
+ character.SetCharacterObjectRotation(newRotation);
+ }
+}
+```
+
+## Testing
+
+Comprehensive tests are provided in `CharacterEntityRuntimeTests.cs` that validate:
+
+- All new API methods function correctly
+- Error handling works as expected
+- GameObject transforms are updated properly
+- Edge cases are handled gracefully
+
+A demonstration script `CharacterEntityRuntimeDemo.cs` is also provided showing practical usage examples.
\ No newline at end of file
diff --git a/Assets/StraightFour/Testing/EntityTests/CharacterEntity_RuntimeAPI_Documentation.md.meta b/Assets/StraightFour/Testing/EntityTests/CharacterEntity_RuntimeAPI_Documentation.md.meta
new file mode 100644
index 0000000..bbf5a99
--- /dev/null
+++ b/Assets/StraightFour/Testing/EntityTests/CharacterEntity_RuntimeAPI_Documentation.md.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
\ No newline at end of file