UnityAccessibilityLib 2.0.0
dotnet add package UnityAccessibilityLib --version 2.0.0
NuGet\Install-Package UnityAccessibilityLib -Version 2.0.0
<PackageReference Include="UnityAccessibilityLib" Version="2.0.0" />
<PackageVersion Include="UnityAccessibilityLib" Version="2.0.0" />
<PackageReference Include="UnityAccessibilityLib" />
paket add UnityAccessibilityLib --version 2.0.0
#r "nuget: UnityAccessibilityLib, 2.0.0"
#:package UnityAccessibilityLib@2.0.0
#addin nuget:?package=UnityAccessibilityLib&version=2.0.0
#tool nuget:?package=UnityAccessibilityLib&version=2.0.0
UnityAccessibilityLib
A reusable library for adding screen reader accessibility to Unity games. Works with MelonLoader, BepInEx, or any Unity mod framework.
Features
- UniversalSpeech integration - P/Invoke wrapper for the UniversalSpeech library with SAPI fallback
- Braille display support - Automatic output to braille displays via screen reader
- High-level speech manager - Duplicate prevention, repeat functionality, speaker formatting
- Text cleaning - Strips Unity rich text tags (
<color>,<size>,<b>, etc.) with extensible custom replacements - Logging abstraction - Integrate with any logging system (MelonLoader, BepInEx, custom)
- Multi-target support - Builds for net6.0, net472, and net35 for broad compatibility with various games
Requirements
- UniversalSpeech.dll in the game directory
- One of:
- .NET 6.0 (IL2CPP games with MelonLoader 0.6+)
- .NET Framework 4.7.2 (Mono games)
- .NET Framework 3.5 (older Mono games, e.g. Unity 2017)
Installation
Option 1: NuGet Package (Recommended)
dotnet add package UnityAccessibilityLib
Or add to your .csproj:
<PackageReference Include="UnityAccessibilityLib" Version="2.0.0" />
Option 2: Project Reference
Add the project to your solution and reference it:
<ProjectReference Include="..\UnityAccessibilityLib\UnityAccessibilityLib.csproj" />
Option 3: DLL Reference
Build the library and reference the DLL:
<Reference Include="UnityAccessibilityLib">
<HintPath>path\to\UnityAccessibilityLib.dll</HintPath>
</Reference>
Quick Start
MelonLoader Setup
using MelonLoader;
using UnityAccessibilityLib;
public class MelonLoggerAdapter : IAccessibilityLogger
{
private readonly MelonLogger.Instance _logger;
public MelonLoggerAdapter(MelonLogger.Instance logger)
{
_logger = logger;
}
public void Msg(string message) => _logger.Msg(message);
public void Warning(string message) => _logger.Warning(message);
public void Error(string message) => _logger.Error(message);
}
public class MyAccessibilityMod : MelonMod
{
public override void OnInitializeMelon()
{
AccessibilityLog.Logger = new MelonLoggerAdapter(LoggerInstance);
if (SpeechManager.Initialize())
{
LoggerInstance.Msg("Speech system ready");
}
}
}
BepInEx Setup
using BepInEx;
using BepInEx.Logging;
using UnityAccessibilityLib;
public class BepInExLoggerAdapter : IAccessibilityLogger
{
private readonly ManualLogSource _logger;
public BepInExLoggerAdapter(ManualLogSource logger)
{
_logger = logger;
}
public void Msg(string message) => _logger.LogInfo(message);
public void Warning(string message) => _logger.LogWarning(message);
public void Error(string message) => _logger.LogError(message);
}
[BepInPlugin("com.example.mymod", "MyAccessibilityMod", "1.0.0")]
public class MyPlugin : BaseUnityPlugin
{
void Awake()
{
AccessibilityLog.Logger = new BepInExLoggerAdapter(Logger);
if (SpeechManager.Initialize())
{
Logger.LogInfo("Speech system ready");
}
}
}
Output Speech
// Dialogue with speaker name
SpeechManager.Output("Phoenix", "Hold it!", TextType.Dialogue);
// Output: "Phoenix: Hold it!"
// Narrator text
SpeechManager.Output(null, "The court fell silent.", TextType.Narrator);
// Output: "The court fell silent."
// Menu/system announcements
SpeechManager.Announce("Save complete", TextType.System);
// Repeat last dialogue (bind to a key)
SpeechManager.RepeatLast();
API Reference
SpeechManager
| Method | Description |
|---|---|
Initialize() |
Initialize the speech system. Returns true on success. |
Output(speaker, text, textType) |
Speak text with optional speaker name. |
Announce(text, textType) |
Speak text without a speaker name. |
RepeatLast() |
Repeat the last dialogue/narrator text. |
Stop() |
Stop current speech. |
ClearRepeatBuffer() |
Clear stored repeat text. |
| Property | Description |
|---|---|
DuplicateWindowSeconds |
Time window for duplicate suppression (default: 0.5s) |
EnableLogging |
Whether to log speech output (default: true) |
EnableBraille |
Whether to output to braille displays (default: true) |
FormatTextOverride |
Custom delegate for text formatting (see Extensibility) |
ShouldStoreForRepeatPredicate |
Custom predicate for repeat storage (see Extensibility) |
TextTypeNames |
Dictionary mapping text type IDs to names for logging |
TextType Constants
| Value | Description |
|---|---|
Dialogue |
Character dialogue (formatted as "Speaker: text") |
Narrator |
Narrator/descriptive text |
Menu |
Menu item text |
MenuChoice |
Menu selection |
System |
System messages |
CustomBase |
Base value (100) for defining custom text types |
UniversalSpeechWrapper
Low-level access to UniversalSpeech:
UniversalSpeechWrapper.Initialize(); // Initialize (called by SpeechManager)
UniversalSpeechWrapper.Speak("text", true); // Speak with interrupt
UniversalSpeechWrapper.DisplayBraille("text"); // Output to braille display
UniversalSpeechWrapper.Stop(); // Stop speech
UniversalSpeechWrapper.IsScreenReaderActive(); // Check if screen reader is running
TextCleaner
Basic usage:
string clean = TextCleaner.Clean("<color=#ff0000>Red text</color>");
// Result: "Red text"
string combined = TextCleaner.CombineLines("Line 1", "<b>Line 2</b>", "Line 3");
// Result: "Line 1 Line 2 Line 3"
Custom text replacements (applied after tag removal):
// Simple string replacement
TextCleaner.AddReplacement("♥", "heart");
TextCleaner.AddReplacement("→", "arrow");
// Regex replacement
TextCleaner.AddRegexReplacement(@"\[(\d+)\]", "footnote $1");
// Clear custom replacements
TextCleaner.ClearReplacements(); // Clear string replacements only
TextCleaner.ClearRegexReplacements(); // Clear regex replacements only
TextCleaner.ClearAllCustomReplacements(); // Clear all
AccessibilityLog
// Set your logger implementation
AccessibilityLog.Logger = new MelonLoggerAdapter(loggerInstance);
// or
AccessibilityLog.Logger = new BepInExLoggerAdapter(loggerInstance);
// Or create a simple console logger for testing
AccessibilityLog.Logger = new ConsoleLogger();
public class ConsoleLogger : IAccessibilityLogger
{
public void Msg(string message) => Console.WriteLine(message);
public void Warning(string message) => Console.WriteLine($"[WARN] {message}");
public void Error(string message) => Console.WriteLine($"[ERROR] {message}");
}
.NET 3.5 Compatibility
The library includes Net35Extensions with polyfills for methods not available in .NET 3.5:
Net35Extensions.IsNullOrWhiteSpace(string)- Use instead ofstring.IsNullOrWhiteSpace
Extensibility
Custom Text Types
Define custom text types for game-specific content:
public static class MyTextTypes
{
public const int Tutorial = TextType.CustomBase + 1; // 101
public const int Combat = TextType.CustomBase + 2; // 102
public const int Inventory = TextType.CustomBase + 3; // 103
}
// Register names for logging
SpeechManager.TextTypeNames = new Dictionary<int, string>
{
{ TextType.Dialogue, "Dialogue" },
{ TextType.Narrator, "Narrator" },
{ MyTextTypes.Tutorial, "Tutorial" },
{ MyTextTypes.Combat, "Combat" },
};
// Use custom types
SpeechManager.Announce("Press A to jump", MyTextTypes.Tutorial);
Custom Text Formatting
Override how text is formatted before output:
SpeechManager.FormatTextOverride = (speaker, text, textType) =>
{
// Custom formatting logic
if (textType == MyTextTypes.Combat)
return $"Combat: {text}";
if (!string.IsNullOrEmpty(speaker))
return $"{speaker} says: {text}";
return text;
};
Custom Repeat Storage
Control which text types are stored for repeat functionality:
SpeechManager.ShouldStoreForRepeatPredicate = (textType) =>
{
// Store dialogue, narrator, and tutorial text for repeat
return textType == TextType.Dialogue
|| textType == TextType.Narrator
|| textType == MyTextTypes.Tutorial;
};
UniversalSpeech Setup
- Download UniversalSpeech from GitHub
- Copy
UniversalSpeech.dll(32-bit or 64-bit depending on the game's architecture) to the game's root directory - The library will automatically use any active screen reader, or fall back to Windows SAPI
Supported screen readers:
- NVDA
- JAWS
- Window-Eyes
- System Access
- Supernova
- ZoomText
- SAPI (fallback)
Migrating from MelonAccessibilityLib
If you're upgrading from the old MelonAccessibilityLib package:
- Update your NuGet package reference from
MelonAccessibilityLibtoUnityAccessibilityLib - Update your
usingstatements fromusing MelonAccessibilityLib;tousing UnityAccessibilityLib;
No API changes - all classes and methods remain the same.
License
MIT License - see LICENSE for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Framework | net35 is compatible. net40 was computed. net403 was computed. net45 was computed. net451 was computed. net452 was computed. net46 was computed. net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 is compatible. net48 was computed. net481 was computed. |
-
.NETFramework 3.5
- No dependencies.
-
.NETFramework 4.7.2
- No dependencies.
-
net6.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.0 | 112 | 1/12/2026 |