Skip to main content
Developer Integration Guidev1.1 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.

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.

Workflow 1: Zero-CodeCanvasLayer 130

Turnkey In-Game Overlay Menu

Drop addons/anyuser into your Godot project and enable it under Project → Project Settings → Plugins. Zero scripting required!

Floating Button & Shortcut Drawer

Injects an unobtrusive floating AnyUser button. Players can click it or press F10 (or controller Back / L3+R3) to open the accessibility drawer.

Custom Shortcut Remapping & Hide Button

Players can hide the on-screen button for a clean HUD and remap the shortcut key (e.g. Shift+F1 or ~), persisted automatically.

.anyuser Profile Import & Export

Players can import their calibrated profile from anyuser.net or save local changes directly to user://profile.anyuser.

Instant Assist Presets

One-click presets: Low Vision (125% scale + high contrast), Reduced Motion (0% shake), Easy Controls (hold toggles), and Sound Comfort (tinnitus cut).

High-Contrast Outlines & Plain English

Clear 2px outlined checkmark boxes and intuitive labels designed specifically for low-vision and non-technical players.

Instant Activation:
Project Settings → Plugins → Enable "AnyUser Accessibility Standard"
Workflow 2: Headless & Custom UIAnyUser Singleton API

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.

Headless Overlay Disable

Set AnyUser.enable_overlay = false to suppress the built-in floating button and drawer completely while keeping all background logic active.

Typed Setters & Real-Time Engine Sync

AnyUser.set_ui_scale(), set_screen_shake(), and set_colorblind_filter() automatically reconfigure viewport scaling, shaders, and audio buses live.

Aim Assist & Target Magnetism

AnyUserInput.apply_aim_assist(origin, aim_dir, targets, radius) calculates magnetism and pulls crosshairs toward targets based on aim_assist_strength.

QTE Auto-Complete & Time Limits

Query AnyUser.get_qte_auto_complete() to bypass rapid button-mashing events, or AnyUser.get_disable_time_limits() to pause countdown pressure.

Hold-to-Toggle & Tremor Debounce

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:

Target Engine:
AnyUserParser.gd
# 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:

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.