Skip to main content
Developer Integration Guidev1.0 Standard Draft-07 Specification

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.

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:

1️⃣

Ingest Profile

Singleton reads profile.anyuser from local app data or persistent user storage on game boot.

2️⃣

Sanitize & Clamp

Values are validated against Draft-07 bounds (e.g. screen_shake clamped 0.0–1.0).

3️⃣

Inject Interceptors

Overrides camera offsets, input event polling, audio bus filters, and UI canvas scale factors.

4️⃣

Render Frame 1

The game launches fully accessible from the opening splash screen and main menu without user intervention.

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:

Target Engine:
AnyUserParser.gd
# AnyUserParser.gd
# Add as an AutoLoad Singleton in Project -> Project Settings -> Autoload
extends Node

var current_profile: Dictionary = {}
var is_loaded: bool = false

signal profile_loaded(profile_data)

func _ready() -> void:
	# Check candidate paths: persistent user data, project root, and addon directories
	var candidate_paths: Array[String] = [
		"user://profile.anyuser",
		"res://profile.anyuser",
		"res://addons/anyuser/profile.anyuser",
		"res://addons/user/profile.anyuser"
	]
	for path in candidate_paths:
		if FileAccess.file_exists(path):
			if load_profile(path):
				break

func load_profile(file_path: String) -> bool:
	if not FileAccess.file_exists(file_path):
		push_warning("AnyUser: Profile not found at %s" % file_path)
		return false
	
	var file := FileAccess.open(file_path, FileAccess.READ)
	var json_str := file.get_as_text()
	file.close()
	
	var test_json_conv := JSON.new()
	var error := test_json_conv.parse(json_str)
	if error != OK:
		push_error("AnyUser: Failed to parse JSON: " + test_json_conv.get_error_message())
		return false
	
	current_profile = test_json_conv.data
	is_loaded = true
	apply_all_interceptors()
	emit_signal("profile_loaded", current_profile)
	print("AnyUser: Profile v%s loaded successfully from %s" % [current_profile.get("version", "1.0"), file_path])
	return true

func apply_all_interceptors() -> void:
	# 1. Zero-Code Drop-In UI Scaling
	var vision: Dictionary = current_profile.get("vision", {})
	if vision.has("ui_scale") and get_tree() and get_tree().root:
		var scale_factor := float(vision["ui_scale"])
		if scale_factor > 0.0:
			if get_tree().root.content_scale_mode == Window.CONTENT_SCALE_MODE_DISABLED:
				get_tree().root.content_scale_mode = Window.CONTENT_SCALE_MODE_CANVAS_ITEMS
			get_tree().root.content_scale_factor = scale_factor

	# 2. Intercept camera shake trauma factor
	if vision.has("screen_shake"):
		var shake_val := float(vision["screen_shake"])
		if has_node("/root/AnyUserCamera"):
			get_node("/root/AnyUserCamera").shake_multiplier = shake_val
		elif get_viewport() and get_viewport().get_camera_2d():
			var cam = get_viewport().get_camera_2d()
			if "shake_multiplier" in cam:
				cam.shake_multiplier = shake_val
	
	# 3. Intercept audio bus filters (mono downmix & tinnitus frequency cut)
	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.0)

Explore every parameter defined in anyuser-schema.json with mathematical bounds, human rationales, and engine hook recipes:

Data Type:

number (float)

Valid Range / Values:

0.0 (Off) to 1.0 (Full)

Standard Default:

1.0

Human / Accessibility Rationale:

Prevents motion sickness, vestibular dysfunction, and migraines caused by violent camera shake during explosions, hits, and recoil.

Recommended Engine Interceptor Hook:Multiply all Camera2D/Camera3D randomized impulse offsets by screen_shake. When 0.0, lock the camera to static transform.

Grassroots Accessibility

Zero-Studio Waiting

Community 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:

Draft-07 Standard Path Spec
Windows 10 / 11Priority 2
%USERPROFILE%\.anyuser\default.anyuserStandard global profile location for all desktop PC games.
Linux / Steam Deck / SteamOSPriority 2
~/.config/anyuser/default.anyuserXDG config directory; also falls back to ~/.anyuser/default.anyuser.
macOSPriority 2
~/Library/Application Support/anyuser/default.anyuserNative macOS Application Support directory path.
Game Portable ModePriority 1 (Override)
<GameRoot>\anyuser_profile.jsonPer-game local override placed directly alongside the game executable.
Mod Framework:
Unity Engine (BepInEx 5/6 + HarmonyX)BepInEx 5/6 • C#

Intercepts Camera transform shake routines and converts hold keys into toggle latches across commercial Unity titles without requiring source code.

Engine Compatibility:
Unity Mono GamesUnity IL2CPP GamesCustom C# Assemblies
Installation & Hooking Instructions:
  1. 1Install BepInEx 5 or 6 into your game's root directory.
  2. 2Drop the compiled AnyUserModWrapper.dll into BepInEx/plugins/.
  3. 3The mod reads %USERPROFILE%\.anyuser\default.anyuser on boot and hooks Camera transforms and Input polling without touching game assemblies.
AnyUserModWrapper.cs
// 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;
        }
    }
}
Anti-Cheat & Fair Play Compliance Advisory

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:

Test Payload (JSON):

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.