AnyUser Developer Portal
Integrate the universal accessibility standard into your game engine or software. With the Behavioral Interceptor pattern, you override camera transforms, input polling, and audio nodes on boot—ensuring players never experience configuration fatigue.
Turnkey in-game accessibility drawer/overlay + headless manual mode with GDScript & C# singletons, AnyUserCamera2D, and shaders.
UPM package featuring AnyUserParser, AnyUserCameraShake, and URP colorblind shaders.
C++ Subsystem, Camera Modifier for shake dampening, and Enhanced Input modifiers.
Zero-dependency package for profile parsing, CSS variable injection, and zero-account URL hash sync.
1-Click Bookmarklet and Manifest V3 extension to inject AnyUser onto any active website.
Public, edge-cached JSON Schema with open CORS at /schema/v1/anyuser-schema.json.
Architecture Principle
The "Behavioral Interceptor" Pattern
Traditional accessibility requires sprawling settings submenus. AnyUser shifts responsibility to engine-level interceptors that apply preferences before frame 1:
Ingest Profile
Singleton reads profile.anyuser from local app data or persistent user storage on game boot.
Sanitize & Clamp
Values are validated against Draft-07 bounds (e.g. screen_shake clamped 0.0–1.0).
Inject Interceptors
Overrides camera offsets, input event polling, audio bus filters, and UI canvas scale factors.
Render Frame 1
The game launches fully accessible from the opening splash screen and main menu without user intervention.
Godot 4 Integration Guide
Turnkey In-Game Overlay vs. Headless Manual API
The official Godot 4 addon provides two complementary ways to integrate accessibility into your game. Use the turnkey overlay for immediate, zero-code settings, or run in headless mode to hook niche accessibility parameters directly into your game's native UI and gameplay systems.
Turnkey In-Game Overlay Menu
Drop addons/anyuser into your Godot project and enable it under Project → Project Settings → Plugins. Zero scripting required!
Injects an unobtrusive floating AnyUser button. Players can click it or press F10 (or controller Back / L3+R3) to open the accessibility drawer.
Players can hide the on-screen button for a clean HUD and remap the shortcut key (e.g. Shift+F1 or ~), persisted automatically.
Players can import their calibrated profile from anyuser.net or save local changes directly to user://profile.anyuser.
One-click presets: Low Vision (125% scale + high contrast), Reduced Motion (0% shake), Easy Controls (hold toggles), and Sound Comfort (tinnitus cut).
Clear 2px outlined checkmark boxes and intuitive labels designed specifically for low-vision and non-technical players.
Project Settings → Plugins → Enable "AnyUser Accessibility Standard"Developer Manual Mode & Engine Hooks
Run AnyUser headlessly to embed settings inside your game's native pause screen and hook niche parameters into gameplay mechanics.
Set AnyUser.enable_overlay = false to suppress the built-in floating button and drawer completely while keeping all background logic active.
AnyUser.set_ui_scale(), set_screen_shake(), and set_colorblind_filter() automatically reconfigure viewport scaling, shaders, and audio buses live.
AnyUserInput.apply_aim_assist(origin, aim_dir, targets, radius) calculates magnetism and pulls crosshairs toward targets based on aim_assist_strength.
Query AnyUser.get_qte_auto_complete() to bypass rapid button-mashing events, or AnyUser.get_disable_time_limits() to pause countdown pressure.
AnyUserInput.is_action_active(&'sprint') turns holds into toggles; is_action_just_pressed_debounced() absorbs tremor-induced duplicate taps.
Interactive Engine Integrator
Drop-in Engine Scripts & Singletons
Select your game engine and the behavioral interceptor you want to implement to generate copy-paste code:
# AnyUserParser.gd (Godot 4 Addon Singleton)
# Auto-registered by plugin.gd or Project Settings -> Globals -> Autoload
extends Node
## Set to false to disable the turnkey overlay drawer (for custom settings UI)
@export var enable_overlay: bool = true
var current_profile: Dictionary = {}
var is_loaded: bool = false
signal profile_loaded(profile_data: Dictionary)
signal profile_changed(profile_data: Dictionary)
func _ready() -> void:
# 1. Discover and load candidate .anyuser profile
var candidate_paths: Array[String] = [
"user://profile.anyuser",
"res://profile.anyuser",
"res://addons/anyuser/profile.anyuser",
]
for path in candidate_paths:
if FileAccess.file_exists(path) and load_profile_from_file(path):
break
# 2. Inject turnkey overlay menu if enabled
if enable_overlay:
_inject_turnkey_overlay()
# --- Programmatic Getters & Setters ---
func get_ui_scale() -> float:
return float(current_profile.get("vision", {}).get("ui_scale", 1.0))
func set_ui_scale(val: float) -> void:
current_profile.get_or_add("vision", {})["ui_scale"] = clampf(val, 0.5, 2.0)
apply_all_interceptors()
profile_changed.emit(current_profile)
func get_screen_shake() -> float:
return float(current_profile.get("vision", {}).get("screen_shake", 1.0))
func set_screen_shake(val: float) -> void:
current_profile.get_or_add("vision", {})["screen_shake"] = clampf(val, 0.0, 1.0)
apply_all_interceptors()
profile_changed.emit(current_profile)
func get_aim_assist_strength() -> float:
return float(current_profile.get("motor", {}).get("aim_assist_strength", 0.0))
func get_qte_auto_complete() -> bool:
return bool(current_profile.get("motor", {}).get("qte_auto_complete", false))
func get_disable_time_limits() -> bool:
return bool(current_profile.get("cognitive", {}).get("disable_time_limits", false))
func is_high_contrast() -> bool:
return bool(current_profile.get("vision", {}).get("high_contrast_mode", false))
func is_tinnitus_frequency_cut() -> bool:
return bool(current_profile.get("audio", {}).get("tinnitus_frequency_cut", false))
func load_profile_from_file(path: String) -> bool:
if not FileAccess.file_exists(path): return false
var file := FileAccess.open(path, FileAccess.READ)
var json := JSON.new()
if json.parse(file.get_as_text()) == OK:
current_profile = json.data
is_loaded = true
apply_all_interceptors()
profile_loaded.emit(current_profile)
return true
return false
func save_profile_to_file(path: String = "user://profile.anyuser") -> bool:
var file := FileAccess.open(path, FileAccess.WRITE)
if file:
file.store_string(JSON.stringify(current_profile, " "))
return true
return false
func apply_all_interceptors() -> void:
# UI Canvas scaling, Screen Shake clamp, Fullscreen Shaders & Audio low-pass
var vision: Dictionary = current_profile.get("vision", {})
if get_tree() and get_tree().root and vision.has("ui_scale"):
get_tree().root.content_scale_factor = float(vision["ui_scale"])
var audio: Dictionary = current_profile.get("audio", {})
var master_idx := AudioServer.get_bus_index("Master")
if master_idx >= 0 and audio.get("tinnitus_frequency_cut", false):
var lpf := AudioEffectLowPassFilter.new()
lpf.cutoff_hz = 4000.0
AudioServer.add_bus_effect(master_idx, lpf)Schema Specification Reference
Interactive Schema Dictionary (v1.1)
Explore every parameter defined in anyuser-schema.json with mathematical bounds, human rationales, and engine hook recipes:
number (float)
0.0 (Off) to 1.0 (Full)
1.0
Prevents motion sickness, vestibular dysfunction, and migraines caused by violent camera shake during explosions, hits, and recoil.
Multiply all Camera2D/Camera3D randomized impulse offsets by screen_shake. When 0.0, lock the camera to static transform.Grassroots Accessibility
Zero-Studio WaitingCommunity Modding & Runtime Wrappers
Commercial studios often take years to patch accessibility into legacy backlogs. Through community modding frameworks—including BepInEx for Unity, GDWeave for Godot, and UE4SS for Unreal Engine—modders can inject the universal .anyuser standard into existing commercial titles today without source code access.
Universal Profile Discovery Standard
All community wrappers inspect these standard OS locations in prioritized order on game boot:
%USERPROFILE%\.anyuser\default.anyuserStandard global profile location for all desktop PC games.~/.config/anyuser/default.anyuserXDG config directory; also falls back to ~/.anyuser/default.anyuser.~/Library/Application Support/anyuser/default.anyuserNative macOS Application Support directory path.<GameRoot>\anyuser_profile.jsonPer-game local override placed directly alongside the game executable.Intercepts Camera transform shake routines and converts hold keys into toggle latches across commercial Unity titles without requiring source code.
- 1Install BepInEx 5 or 6 into your game's root directory.
- 2Drop the compiled AnyUserModWrapper.dll into BepInEx/plugins/.
- 3The mod reads %USERPROFILE%\.anyuser\default.anyuser on boot and hooks Camera transforms and Input polling without touching game assemblies.
// AnyUserModWrapper.cs
// Universal Accessibility Wrapper for Unity Games (BepInEx 5/6 + HarmonyX)
// Reads standard OS-level AnyUser profile and intercepts camera shake & hold inputs.
using System;
using System.IO;
using System.Collections.Generic;
using BepInEx;
using HarmonyLib;
using UnityEngine;
namespace AnyUser.ModWrapper
{
[BepInPlugin("net.anyuser.modwrapper", "AnyUser Accessibility Wrapper", "1.0.0")]
public class AnyUserPlugin : BaseUnityPlugin
{
public static AnyUserProfile ActiveProfile { get; private set; } = new AnyUserProfile();
private Harmony harmony;
private void Awake()
{
Logger.LogInfo("AnyUser: Initializing Universal Accessibility Interceptor...");
LoadAnyUserProfile();
harmony = new Harmony("net.anyuser.modwrapper");
harmony.PatchAll();
Logger.LogInfo($"AnyUser: Profile loaded (Shake={ActiveProfile.screen_shake * 100}%, HoldToToggle={ActiveProfile.toggle_instead_of_hold})");
}
private void LoadAnyUserProfile()
{
// Standard AnyUser Discovery Paths
string userHome = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
string[] discoveryPaths = new string[]
{
Path.Combine(Paths.GameRootPath, "anyuser_profile.json"),
Path.Combine(userHome, ".anyuser", "default.anyuser"),
Path.Combine(userHome, ".config", "anyuser", "default.anyuser")
};
foreach (string path in discoveryPaths)
{
if (File.Exists(path))
{
try
{
string json = File.ReadAllText(path);
ActiveProfile = AnyUserProfile.FromJson(json);
Logger.LogInfo($"AnyUser: Successfully loaded profile from: {path}");
return;
}
catch (Exception ex)
{
Logger.LogWarning($"AnyUser: Failed reading profile at {path}: {ex.Message}");
}
}
}
Logger.LogWarning("AnyUser: No .anyuser profile found in standard paths. Using defaults.");
}
}
// Harmony Patch: Camera Shake Interceptor
// Clamps Camera localPosition offsets to the profile's screen_shake multiplier
[HarmonyPatch(typeof(Camera), "OnPreRender")]
public static class CameraShakeInterceptorPatch
{
[HarmonyPrefix]
public static void Prefix(Camera __instance)
{
if (AnyUserPlugin.ActiveProfile.screen_shake < 1.0f && __instance == Camera.main)
{
// Scale displacement offset towards center anchor
Vector3 currentLocal = __instance.transform.localPosition;
__instance.transform.localPosition = Vector3.Lerp(Vector3.zero, currentLocal, AnyUserPlugin.ActiveProfile.screen_shake);
}
}
}
// Harmony Patch: Hold-to-Toggle Input Interceptor
// Latches discrete key presses into continuous toggle states when requested
[HarmonyPatch(typeof(Input), nameof(Input.GetKey), new Type[] { typeof(KeyCode) })]
public static class InputHoldToTogglePatch
{
private static readonly Dictionary<KeyCode, bool> toggleStates = new Dictionary<KeyCode, bool>();
private static readonly HashSet<KeyCode> targetedHoldKeys = new HashSet<KeyCode>
{
KeyCode.LeftShift, KeyCode.LeftControl, KeyCode.C, KeyCode.F, KeyCode.E
};
[HarmonyPostfix]
public static void Postfix(KeyCode key, ref bool __result)
{
if (!AnyUserPlugin.ActiveProfile.toggle_instead_of_hold || !targetedHoldKeys.Contains(key))
return;
if (Input.GetKeyDown(key))
{
toggleStates[key] = !toggleStates.GetValueOrDefault(key, false);
}
if (toggleStates.ContainsKey(key))
{
__result = toggleStates[key];
}
}
}
[Serializable]
public class AnyUserProfile
{
public float screen_shake = 0.0f;
public bool toggle_instead_of_hold = true;
public float ui_scale = 1.0f;
public bool high_contrast_mode = false;
public static AnyUserProfile FromJson(string json)
{
var profile = new AnyUserProfile();
if (json.Contains("\"screen_shake\":"))
{
var match = System.Text.RegularExpressions.Regex.Match(json, "\"screen_shake\"\\s*:\\s*([0-9.]+)");
if (match.Success && float.TryParse(match.Groups[1].Value, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float shake))
profile.screen_shake = Mathf.Clamp01(shake);
}
if (json.Contains("\"toggle_instead_of_hold\":"))
{
profile.toggle_instead_of_hold = json.Contains("\"toggle_instead_of_hold\": true") || json.Contains("\"toggle_instead_of_hold\":true");
}
return profile;
}
}
}AnyUser accessibility wrappers operate exclusively on client-side camera transforms, visual presentation, audio buses, and physical motor accessibility. For titles protected by kernel anti-cheat (e.g., Easy Anti-Cheat, BattlEye), deploy wrappers only in single-player or cooperative PvE modes. For competitive multiplayer, urge developers to integrate our official zero-dependency engine SDK directly.
Created an AnyUser Wrapper for another game?
Share your mod with thousands of players! Submit your wrapper to the official AnyUser community repository.
Developer Sandbox
Live JSON Schema Validator
Paste any .anyuser JSON artifact to test compliance against the Draft-07 specification in real time:
Have feedback or building a new engine SDK?
AnyUser is created as part of Cwtch & Code. Reach out at [email protected] or contribute via GitHub.