diff --git a/ChatBoxHud/ChatBoxHud.csproj b/ChatBoxHud/ChatBoxHud.csproj
deleted file mode 100644
index 1b27897..0000000
--- a/ChatBoxHud/ChatBoxHud.csproj
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
- ChatBoxHud
-
-
diff --git a/ChatBoxHud/Main.cs b/ChatBoxHud/Main.cs
deleted file mode 100644
index 107e8e6..0000000
--- a/ChatBoxHud/Main.cs
+++ /dev/null
@@ -1,438 +0,0 @@
-using System.Text;
-using ABI_RC.Core.Player;
-using ABI_RC.Core.Networking.IO.Social;
-using ABI_RC.Core.UI;
-using ABI_RC.Core.UI.Hud;
-using ABI_RC.Systems.ChatBox;
-using ABI_RC.Systems.Communications.Settings;
-using ABI_RC.Systems.GameEventSystem;
-using ABI_RC.Systems.PlayerColors;
-using MelonLoader;
-using UnityEngine;
-
-namespace NAK.ChatBoxHud;
-
-public class ChatBoxHudMod : MelonMod
-{
- public enum HudTarget { Disabled, LookAt, Nearest, LookAtThenNearest }
- public enum SourceFilter { None, FriendsOnly, Everyone }
- public enum MaxUsersOnHud { One, Two, Three }
-
- private const int MaxLines = 4;
- private const int BaseCPL = 62;
- private const int BaseSize = 80;
- private const int MinSize = 50;
- private const int ShrinkAt = 3;
- private const float MinLife = 5f;
- private const float MaxLife = 20f;
- private const float WPM = 250f;
- private const float CPW = 5f;
- private const float LookAngle = 20f;
- private const float FadePct = 0.2f;
- private const int MsgCap = 1000;
-
- private static readonly MelonPreferences_Category Cat =
- MelonPreferences.CreateCategory(nameof(ChatBoxHud));
-
- internal static readonly MelonPreferences_Entry EntryHudMode =
- Cat.CreateEntry("hud_mode", HudTarget.LookAtThenNearest, "HUD Target Mode");
-
- internal static readonly MelonPreferences_Entry EntryHudFilter =
- Cat.CreateEntry("hud_filter", SourceFilter.Everyone, "Chat Filter",
- description: "Whose chat messages appear on the HUD.");
-
- internal static readonly MelonPreferences_Entry EntryMaxUsersOnHud =
- Cat.CreateEntry("max_users_on_hud", MaxUsersOnHud.Three, "Max Users on HUD",
- description: "How many users can be stacked on the HUD when multiple users chat at once.");
-
- internal static readonly MelonPreferences_Entry EntryUsePlayerColors =
- Cat.CreateEntry("player_colors", true, "Use Player Colors",
- description: "Use player-chosen colors for names instead of friend colors.");
-
- private static readonly Dictionary Buffers = new();
- private static readonly StringBuilder SB = new();
- private static readonly int[] VisSlots = new int[MaxLines * 3 + 1];
-
- private static PortalHudIndicator _hud;
-
- #region Slot System
-
- // Stable slot list: once a user occupies an index they keep it until
- // all their messages expire or they leave range. New users append to
- // the first open position. This prevents blocks from jumping around
- // when someone else sends a new message.
- private static readonly List _slotIds = new();
- private static bool _hudActive;
-
- private struct Candidate
- {
- public string Id, Name;
- public Vector3 Pos;
- public float Score; // lower = higher priority
- }
-
- private static readonly List _candidates = new();
- private static readonly Dictionary _candidateLookup = new();
-
- #endregion
-
- private struct Incoming
- {
- public string Id, Name, Text;
- public ChatBoxAPI.MessageSource Source;
- }
-
- private class Msg
- {
- public string[] Lines;
- public int Size;
- public float Stamp, Life;
- public ChatBoxAPI.MessageSource Source;
- }
-
- private class ChatBuf
- {
- public string Id;
- public readonly List Msgs = new();
- }
-
- public override void OnInitializeMelon()
- {
- ChatBoxAPI.OnMessageReceived += OnReceive;
- CVRGameEventSystem.Initialization.OnPlayerSetupStart.AddListener(OnPlayerSetupStart);
- }
-
- private static void OnPlayerSetupStart()
- {
- Transform src = HudController.Instance.PortalHudIndicator.transform;
- GameObject go = UnityEngine.Object.Instantiate(src.gameObject, src.parent);
- go.transform.SetLocalPositionAndRotation(src.localPosition, src.localRotation);
- go.transform.localScale = src.localScale;
- _hud = go.GetComponent();
- }
-
- public override void OnUpdate()
- {
- Tick();
- }
-
- private static void Tick()
- {
- if (_hud == null || EntryHudMode.Value == HudTarget.Disabled) { Hide(); return; }
- Prune();
-
- int maxSlots = (int)EntryMaxUsersOnHud.Value + 1;
- GatherCandidates();
-
- // Remove slots whose user has no messages left or is no longer
- // a valid candidate (walked out of range, left the instance, etc.)
- for (int i = _slotIds.Count - 1; i >= 0; i--)
- {
- string sid = _slotIds[i];
- bool dead = !_candidateLookup.ContainsKey(sid)
- || !Buffers.TryGetValue(sid, out ChatBuf b)
- || b.Msgs.Count == 0;
- if (dead) _slotIds.RemoveAt(i);
- }
-
- // If the setting was lowered at runtime, trim from the end
- while (_slotIds.Count > maxSlots)
- _slotIds.RemoveAt(_slotIds.Count - 1);
-
- // Fill empty slots from best-scored candidates not already slotted
- if (_slotIds.Count < maxSlots && _candidates.Count > 0)
- {
- _candidates.Sort((a, b) => a.Score.CompareTo(b.Score));
- foreach (Candidate c in _candidates)
- {
- if (_slotIds.Count >= maxSlots) break;
- if (_slotIds.Contains(c.Id)) continue;
- _slotIds.Add(c.Id);
- }
- }
-
- if (_slotIds.Count == 0) { Hide(); return; }
-
- // Render every active slot into one combined string
- SB.Clear();
- bool first = true;
- foreach (string slotId in _slotIds)
- {
- if (!_candidateLookup.TryGetValue(slotId, out Candidate cand)) continue;
- if (!Buffers.TryGetValue(slotId, out ChatBuf buf) || buf.Msgs.Count == 0) continue;
-
- if (!first) SB.Append('\n');
- RenderBlock(SB, cand.Name, cand.Id, buf, cand.Pos);
- first = false;
- }
-
- _hud.SetText(SB.ToString());
- if (!_hudActive) { _hudActive = true; _hud.Activate(); }
- }
-
- private static void Hide()
- {
- if (!_hudActive) return;
- _hud?.Deactivate();
- _hudActive = false;
- _slotIds.Clear();
- }
-
- // Scores every player who has buffered messages, is in comms range,
- // and passes the current HudTarget mode filter.
- private static void GatherCandidates()
- {
- _candidates.Clear();
- _candidateLookup.Clear();
-
- HudTarget mode = EntryHudMode.Value;
- Camera cam = Camera.main;
- if (cam == null) return;
-
- Vector3 lp = PlayerSetup.Instance.GetPlayerPosition();
- Vector3 cf = cam.transform.forward;
- Vector3 cp = cam.transform.position;
- float commsRange = Comms_SettingsHandler.FalloffDistance + 1;
-
- foreach (KeyValuePair kvp in Buffers)
- {
- if (kvp.Value.Msgs.Count == 0) continue;
- if (!CVRPlayerManager.Instance.TryGetPlayerBase(kvp.Key, out PlayerBase pb)) continue;
-
- Vector3 pp = pb.GetPlayerWorldRootPosition();
- float d = Vector3.Distance(lp, pp);
- if (d > commsRange) continue;
-
- string uid = kvp.Key;
- string n = pb.PlayerUsername ?? "???";
- float angle = Vector3.Angle(cf, (pp - cp).normalized);
- bool inLook = angle < LookAngle;
-
- float score;
- switch (mode)
- {
- case HudTarget.LookAt:
- if (!inLook) continue; // hard filter
- score = angle;
- break;
- case HudTarget.Nearest:
- score = d;
- break;
- case HudTarget.LookAtThenNearest:
- // look-at targets always rank above distance-only
- score = inLook ? angle : 1000f + d;
- break;
- default:
- continue;
- }
-
- Candidate c = new Candidate { Id = uid, Name = n, Pos = pp, Score = score };
- _candidates.Add(c);
- _candidateLookup[uid] = c;
- }
- }
-
- private static void RenderBlock(StringBuilder sb, string playerName, string playerId,
- ChatBuf buf, Vector3 tgtPos)
- {
- Camera cam = PlayerSetup.Instance.activeCam;
- float now = Time.time;
-
- // direction arrows from camera angle to target
- float la = 0f, ra = 0f;
- {
- Vector3 toT = tgtPos - cam.transform.position;
- Vector3 fwd = cam.transform.forward;
- toT.y = 0f;
- fwd.y = 0f;
- if (toT.sqrMagnitude > 0.001f && fwd.sqrMagnitude > 0.001f)
- {
- float sa = Vector3.SignedAngle(fwd.normalized, toT.normalized, Vector3.up);
- float abs = Mathf.Abs(sa);
- if (abs > LookAngle)
- {
- float t = Mathf.InverseLerp(LookAngle, 90f, abs);
- float v = Mathf.Clamp01(t);
- la = sa < 0f ? v : 0f;
- ra = sa > 0f ? v : 0f;
- }
- }
- }
-
- // name color: player colors or friend-based fallback
- string hex;
- if (EntryUsePlayerColors.Value)
- {
- PlayerColors pc = PlayerColorsManager.GetPlayerColors(playerId);
- hex = "#" + ColorUtility.ToHtmlStringRGB(pc.PrimaryColor);
- }
- else hex = Friends.FriendsWith(playerId) ? "#4FC3F7" : "#E0E0E0";
-
- // header line
- AppendAlpha(sb, la); sb.Append("\u25C4 ");
- sb.Append("')
- .Append(Esc(playerName)).Append("");
- AppendAlpha(sb, ra); sb.Append(" \u25BA\n");
-
- // allocate visible line count per message, newest gets priority
- int count = 0, budget = MaxLines;
- for (int i = buf.Msgs.Count - 1; i >= 0 && budget > 0; i--)
- {
- int v = Mathf.Min(buf.Msgs[i].Lines.Length, budget);
- VisSlots[count++] = v;
- budget -= v;
- }
-
- // render oldest to newest (slots were stored newest-first, so reverse)
- int startIdx = buf.Msgs.Count - count;
- for (int i = 0; i < count; i++)
- {
- int mi = startIdx + i;
- int vis = VisSlots[count - 1 - i];
- Msg m = buf.Msgs[mi];
- float age = now - m.Stamp;
-
- float fadeAt = m.Life * (1f - FadePct);
- float alpha = age < fadeAt ? 1f
- : Mathf.Clamp01(1f - (age - fadeAt) / (m.Life * FadePct));
- byte a = (byte)(alpha * 255);
-
- // smooth line-by-line scroll for overflowing messages
- int off = 0;
- if (m.Lines.Length > vis)
- {
- float usable = m.Life * (1f - FadePct);
- float perLine = usable / m.Lines.Length;
- float initHold = perLine * vis;
- off = Mathf.Min(
- (int)(Mathf.Max(0f, age - initHold) / perLine),
- m.Lines.Length - vis);
- }
-
- for (int j = 0; j < vis; j++)
- {
- sb.Append("')
- .Append("")
- .Append(m.Lines[off + j])
- .Append("\n");
- }
- }
-
- // trim trailing newline from this block
- if (sb.Length > 0 && sb[sb.Length - 1] == '\n') sb.Length--;
- }
-
- private static void AppendAlpha(StringBuilder sb, float a01)
- {
- sb.Append("');
- }
-
- private static void OnReceive(ChatBoxAPI.ChatBoxMessage msg)
- {
- if (msg.Source != ChatBoxAPI.MessageSource.Internal) return;
- if (string.IsNullOrWhiteSpace(msg.Message)) return;
-
- string sid = msg.SenderGuid;
- if (!CVRPlayerManager.Instance.TryGetPlayerBase(sid, out PlayerBase pb)) return;
-
- SourceFilter filter = EntryHudFilter.Value;
- if (filter == SourceFilter.None) return;
- if (filter == SourceFilter.FriendsOnly && !Friends.FriendsWith(sid)) return;
-
- Store(new Incoming
- {
- Id = sid,
- Name = pb.PlayerUsername ?? "???",
- Text = msg.Message,
- Source = msg.Source
- });
- }
-
- private static void Store(in Incoming inc)
- {
- if (!Buffers.TryGetValue(inc.Id, out ChatBuf buf))
- {
- buf = new ChatBuf { Id = inc.Id };
- Buffers[inc.Id] = buf;
- }
-
- string text = inc.Text;
- if (text.Length > MsgCap) text = text.Substring(0, MsgCap);
- text = text.Replace("\r", "");
-
- Fit(text, out string[] lines, out int size);
- for (int i = 0; i < lines.Length; i++) lines[i] = Esc(lines[i]);
-
- buf.Msgs.Add(new Msg
- {
- Lines = lines,
- Size = size,
- Stamp = Time.time,
- Life = Life(text.Length),
- Source = inc.Source
- });
-
- while (buf.Msgs.Count > MaxLines * 3)
- buf.Msgs.RemoveAt(0);
- }
-
- private static void Prune()
- {
- float now = Time.time;
- foreach (ChatBuf buf in Buffers.Values)
- buf.Msgs.RemoveAll(m => now - m.Stamp > m.Life);
- }
-
- // shrink text size until line count is manageable
- private static void Fit(string text, out string[] lines, out int size)
- {
- lines = Wrap(text, BaseCPL);
- size = BaseSize;
- if (lines.Length <= ShrinkAt) return;
-
- for (int s = BaseSize - 5; s >= MinSize; s -= 5)
- {
- int cpl = (int)(BaseCPL * BaseSize / (float)s);
- string[] attempt = Wrap(text, cpl);
- lines = attempt; size = s;
- if (attempt.Length <= ShrinkAt) return;
- }
- }
-
- // word wrap respecting embedded newlines
- private static string[] Wrap(string text, int max)
- {
- if (string.IsNullOrEmpty(text)) return new[] { string.Empty };
-
- List result = new List(4);
- foreach (string seg in text.Split('\n'))
- {
- if (seg.Length <= max) { result.Add(seg); continue; }
-
- StringBuilder cur = new StringBuilder(max);
- foreach (string w in seg.Split(' '))
- {
- if (w.Length == 0) continue;
- if (w.Length > max)
- {
- if (cur.Length > 0) { result.Add(cur.ToString()); cur.Clear(); }
- for (int c = 0; c < w.Length; c += max)
- result.Add(w.Substring(c, Math.Min(max, w.Length - c)));
- continue;
- }
- if (cur.Length == 0) cur.Append(w);
- else if (cur.Length + 1 + w.Length <= max) cur.Append(' ').Append(w);
- else { result.Add(cur.ToString()); cur.Clear(); cur.Append(w); }
- }
- if (cur.Length > 0) result.Add(cur.ToString());
- }
- return result.ToArray();
- }
-
- private static float Life(int chars)
- {
- return Mathf.Clamp(MinLife + chars * (60f / (WPM * CPW)), MinLife, MaxLife);
- }
-
- private static string Esc(string s) => s.Replace("<", "<\u200B");
-}
\ No newline at end of file
diff --git a/ChatBoxHud/Properties/AssemblyInfo.cs b/ChatBoxHud/Properties/AssemblyInfo.cs
deleted file mode 100644
index a6cd27b..0000000
--- a/ChatBoxHud/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using MelonLoader;
-using NAK.ChatBoxHud.Properties;
-using System.Reflection;
-
-[assembly: AssemblyVersion(AssemblyInfoParams.Version)]
-[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)]
-[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)]
-[assembly: AssemblyTitle(nameof(NAK.ChatBoxHud))]
-[assembly: AssemblyCompany(AssemblyInfoParams.Author)]
-[assembly: AssemblyProduct(nameof(NAK.ChatBoxHud))]
-
-[assembly: MelonInfo(
- typeof(NAK.ChatBoxHud.ChatBoxHudMod),
- nameof(NAK.ChatBoxHud),
- AssemblyInfoParams.Version,
- AssemblyInfoParams.Author,
- downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ChatBoxHud"
-)]
-
-[assembly: MelonGame("ChilloutVR", "ChilloutVR")]
-[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
-[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
-[assembly: MelonColor(255, 246, 25, 99)] // red-pink
-[assembly: MelonAuthorColor(255, 158, 21, 32)] // red
-[assembly: HarmonyDontPatchAll]
-
-namespace NAK.ChatBoxHud.Properties;
-internal static class AssemblyInfoParams
-{
- public const string Version = "1.0.0";
- public const string Author = "NotAKidoS";
-}
\ No newline at end of file
diff --git a/ChatBoxHud/README.md b/ChatBoxHud/README.md
deleted file mode 100644
index 126be0a..0000000
--- a/ChatBoxHud/README.md
+++ /dev/null
@@ -1,14 +0,0 @@
-# ChatBoxHud
-
-Shows nearby ChatBox messages directly on your HUD so you can read them comfortably in VR without breaking your neck.
-
----
-
-Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI.
-https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games
-
-> This mod is an independent creation not affiliated with, supported by, or approved by Alpha Blend Interactive.
-
-> Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use.
-
-> To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive.
diff --git a/ChatBoxHud/format.json b/ChatBoxHud/format.json
deleted file mode 100644
index cd46a8b..0000000
--- a/ChatBoxHud/format.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "_id": -1,
- "name": "ChatBoxHud",
- "modversion": "1.0.0",
- "gameversion": "2026r181",
- "loaderversion": "0.7.2",
- "modtype": "Mod",
- "author": "NotAKidoS",
- "description": "Shows nearby ChatBox messages directly on your HUD so you can read them comfortably in VR without breaking your neck.",
- "searchtags": [
- "chat",
- "box",
- "hud",
- "indicator",
- "captions"
- ],
- "requirements": [
- ],
- "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r49/ChatBoxHud.dll",
- "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ChatBoxHud/",
- "changelog": "- Initial release",
- "embedcolor": "#f61963"
-}
\ No newline at end of file
diff --git a/README.md b/README.md
index 9b18896..79bc57d 100644
--- a/README.md
+++ b/README.md
@@ -6,26 +6,25 @@
| Name | Description | Download |
|------|-------------|----------|
-| [ASTExtension](ASTExtension/README.md) | Extension mod for [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool): | No Download |
-| [ChatBoxHud](ChatBoxHud/README.md) | Shows nearby ChatBox messages directly on your HUD so you can read them comfortably in VR without breaking your neck. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r49/ChatBoxHud.dll) |
+| [ASTExtension](ASTExtension/README.md) | Extension mod for [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool): | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/ASTExtension.dll) |
| [ConfigureCalibrationPose](ConfigureCalibrationPose/README.md) | Select FBT calibration pose. | No Download |
-| [CustomSpawnPoint](CustomSpawnPoint/README.md) | Replaces the unused Images button in the World Details page with a button to set a custom spawn point. | No Download |
-| [DesktopInteractions](DesktopInteractions/README.md) | Adds IK-driven hand gestures to your avatar in Desktop: earpiece grab (GMOD-style) when typing in ChatBox, and binocular cupping when zooming. Both gestures are toggleable in settings. | No Download |
-| [DoubleTapJumpToExitSeat](DoubleTapJumpToExitSeat/README.md) | Replaces seat exit controls with a double-tap of the jump button, avoiding accidental exits from joystick drift or opening the menu. | No Download |
-| [ESCBothMenus](ESCBothMenus/README.md) | Makes the Quick Menu appear when pressing ESC in Desktop. Pressing twice will open straight to Main Menu. | No Download |
-| [FuckToes](FuckToes/README.md) | Prevents VRIK from autodetecting toes in Halfbody or Fullbody. | No Download |
-| [PlapPlapForAll](PlapPlapForAll/README.md) | Penetrator SFX mod which adds Noach's PlapPlap prefab to any detected DPS setup on avatars that do not already have it. | No Download |
-| [PropLoadingHexagon](PropLoadingHexagon/README.md) | https://github.com/NotAKidoS/NAK_CVR_Mods/assets/37721153/a892c765-71c1-47f3-a781-bdb9b60ba117 | No Download |
-| [PropsButBetter](PropsButBetter/README.md) | Prop quality-of-life suite. Adds a few new ways to interact with and manage Props. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r49/PropsButBetter.dll) |
-| [RCCVirtualSteeringWheel](RCCVirtualSteeringWheel/README.md) | Allows you to physically grab rigged RCC steering wheels in VR to provide steering input. No explicit setup required other than defining the Steering Wheel transform within the RCC component. | No Download |
-| [RelativeSyncJitterFix](RelativeSyncJitterFix/README.md) | Relative sync jitter fix is the single harmony patch that could not make it into the native release of RelativeSync. | No Download |
-| [ShareBubbles](ShareBubbles/README.md) | Share Bubbles! Allows you to drop down bubbles containing Avatars & Props. Requires both users to have the mod installed. Synced over Mod Network. | No Download |
-| [ShowPlayerInSelfMirror](ShowPlayerInSelfMirror/README.md) | Adds an option in the Quick Menu selected player page to show the target player's avatar in your self mirror. | No Download |
-| [SmootherRay](SmootherRay/README.md) | Smoothes your controller while the raycast lines are visible. | No Download |
+| [CustomSpawnPoint](CustomSpawnPoint/README.md) | Replaces the unused Images button in the World Details page with a button to set a custom spawn point. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/CustomSpawnPoint.dll) |
+| [DesktopInteractions](DesktopInteractions/README.md) | Adds IK-driven hand gestures to your avatar in Desktop: earpiece grab (GMOD-style) when typing in ChatBox, and binocular cupping when zooming. Both gestures are toggleable in settings. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/DesktopInteractions.dll) |
+| [DoubleTapJumpToExitSeat](DoubleTapJumpToExitSeat/README.md) | Replaces seat exit controls with a double-tap of the jump button, avoiding accidental exits from joystick drift or opening the menu. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/DoubleTapJumpToExitSeat.dll) |
+| [ESCBothMenus](ESCBothMenus/README.md) | Makes the Quick Menu appear when pressing ESC in Desktop. Pressing twice will open straight to Main Menu. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/ESCBothMenus.dll) |
+| [FuckToes](FuckToes/README.md) | Prevents VRIK from autodetecting toes in Halfbody or Fullbody. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/FuckToes.dll) |
+| [PlapPlapForAll](PlapPlapForAll/README.md) | Penetrator SFX mod which adds Noach's PlapPlap prefab to any detected DPS setup on avatars that do not already have it. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/PlapPlapForAll.dll) |
+| [PropLoadingHexagon](PropLoadingHexagon/README.md) | https://github.com/NotAKidoS/NAK_CVR_Mods/assets/37721153/a892c765-71c1-47f3-a781-bdb9b60ba117 | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/PropLoadingHexagon.dll) |
+| [PropsButBetter](PropsButBetter/README.md) | Prop quality-of-life suite. Adds a few new ways to interact with and manage Props. | No Download |
+| [RCCVirtualSteeringWheel](RCCVirtualSteeringWheel/README.md) | Allows you to physically grab rigged RCC steering wheels in VR to provide steering input. No explicit setup required other than defining the Steering Wheel transform within the RCC component. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/RCCVirtualSteeringWheel.dll) |
+| [RelativeSyncJitterFix](RelativeSyncJitterFix/README.md) | Relative sync jitter fix is the single harmony patch that could not make it into the native release of RelativeSync. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/RelativeSyncJitterFix.dll) |
+| [ShareBubbles](ShareBubbles/README.md) | Share Bubbles! Allows you to drop down bubbles containing Avatars & Props. Requires both users to have the mod installed. Synced over Mod Network. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/ShareBubbles.dll) |
+| [ShowPlayerInSelfMirror](ShowPlayerInSelfMirror/README.md) | Adds an option in the Quick Menu selected player page to show the target player's avatar in your self mirror. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/ShowPlayerInSelfMirror.dll) |
+| [SmootherRay](SmootherRay/README.md) | Smoothes your controller while the raycast lines are visible. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/SmootherRay.dll) |
| [Stickers](Stickers/README.md) | Stickers! Allows you to place small images on any surface. Requires both users to have the mod installed. Synced over Mod Network. | No Download |
-| [ThirdPerson](ThirdPerson/README.md) | Original repo: https://github.com/oestradiol/CVR-Mods | No Download |
-| [Tinyboard](Tinyboard/README.md) | Makes the keyboard small and smart. | No Download |
-| [YouAreMyPropNowWeAreHavingSoftTacosLater](YouAreMyPropNowWeAreHavingSoftTacosLater/README.md) | Lets you bring held, attached, and occupied props through world loads. This is configurable in the mod settings. | No Download |
+| [ThirdPerson](ThirdPerson/README.md) | Original repo: https://github.com/oestradiol/CVR-Mods | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/ThirdPerson.dll) |
+| [Tinyboard](Tinyboard/README.md) | Makes the keyboard small and smart. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/Tinyboard.dll) |
+| [YouAreMyPropNowWeAreHavingSoftTacosLater](YouAreMyPropNowWeAreHavingSoftTacosLater/README.md) | Lets you bring held, attached, and occupied props through world loads. This is configurable in the mod settings. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/YouAreMyPropNowWeAreHavingSoftTacosLater.dll) |
### Experimental Mods
@@ -34,9 +33,9 @@
| [ByeByePerformanceThankYouAMD](.Experimental/ByeByePerformanceThankYouAMD/README.md) | Fixes search terms that use spaces. | No Download |
| [CVRLuaToolsExtension](.Experimental/CVRLuaToolsExtension/README.md) | Extension mod for [CVRLuaTools](https://github.com/NotAKidoS/CVRLuaTools) Hot Reload functionality. | No Download |
| [CustomRichPresence](.Experimental/CustomRichPresence/README.md) | Lets you customize the Steam & Discord rich presence messages & values. | No Download |
-| [LuaNetworkVariables](.Experimental/LuaNetworkVariables/README.md) | Adds a simple module for creating network variables & events *kinda* similar to Garry's Mod. | No Download |
+| [LuaNetworkVariables](.Experimental/LuaNetworkVariables/README.md) | Adds a simple module for creating network variables & events *kinda* similar to Garry's Mod. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/LuaNetworkVariables.dll) |
| [LuaTTS](.Experimental/LuaTTS/README.md) | Provides access to the built-in text-to-speech (TTS) functionality to lua scripts. Allows you to make the local player speak. | No Download |
-| [OriginShift](.Experimental/OriginShift/README.md) | Experimental mod that allows world origin to be shifted to prevent floating point precision issues. | No Download |
+| [OriginShift](.Experimental/OriginShift/README.md) | Experimental mod that allows world origin to be shifted to prevent floating point precision issues. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/OriginShift.dll) |
| [ScriptingSpoofer](.Experimental/ScriptingSpoofer/README.md) | Prevents **local** scripts from accessing your Username or UserID by spoofing them with random values each session. | No Download |