LoveTriggerSDK · Open Source · GNU GPL v3 · Unity 2023

CONSENT IS NOT A FEATURE.
IT IS THE ARCHITECTURE.

LoveTriggerSDK · Eroticissima · v3 · 2026

The open-source Unity framework powering every interaction in Eroticissima. A complete system for building consent-first, gender-free, multiplayer intimate experiences in VR, available now to any developer who wants to build something the industry hasn't bothered to make.

Unity 2023 LTS Photon Fusion 2 FinalIK / VRIK Cinemachine GNU GPL v3 Active Development Docs in Progress
WHAT THE SDK ACTUALLY DOES
01 · The Pipeline

A complete pipeline for building intimate interactions between avatars in Unity, from authoring a motion sequence to delivering it across a multiplayer network with consent confirmed at every step.

02 · What It Handles

The consent handshake between players. VRIK blending that makes avatars feel inhabited. Timeline sequencing for cinematic encounters. NPC partner AI running through the same consent pipeline as a human player.

03 · The Difference

What makes it different is not the architecture, it is what the architecture refuses to allow. No interaction can be forced. No avatar touched without agreement. Enforced at the network layer before any animation plays.

HOW CONSENT WORKS IN THE SDK
Not a UI layer. Not a setting. The gate every interaction passes through human player or NPC, no exceptions, no bypass.
IDLE
DETECTION
PROMPTED
CONSENT PENDING
EXECUTING
RESTORING
IDLE
The player moves freely. VRIK is at full weight. Nothing is locked. This is the baseline state the system always returns to, after any sequence, completed or interrupted.
WHAT THE SDK MAKES POSSIBLE

Multiplayer Intimate VR

Two real players. Custom non-binary avatars. A private room. A shared LoveTrigger library they build together.

The SDK handles networking, consent, avatar embodiment, and motion playback. You design the world and the interactions.

Consent-First NPC System

Solo experiences where NPC partners respond through the same consent pipeline as human players, with configurable hesitation arc, relationship state that evolves, and audio banks keyed to ConsentType.

Even AlwaysAccept runs through the gate.

Custom LoveTrigger Collection

Author your own motion library using LoveTriggerSO ScriptableObjects. Bring clips into Unity, attach metadata, and the SDK handles delivery.

Collections can be sold through the marketplace under your own IP.

TECHNICAL STACK
Designed for anyone with Unity experience. No VR or networking background required, the SDK abstracts Photon Fusion and FinalIK behind clean, documented APIs. If you can author a ScriptableObject, you can author a LoveTrigger.
Engine & Packages
Unity Version2023 LTS
FinalIK (VRIK)Required for VR Asset Store · v2.x
Photon Fusion 2Required Photon Dashboard · v2.x
CinemachineFree Package Manager · v2.x
Input SystemFree Package Manager · v1.7+
XR ManagementOptional Package Manager · v4.x
Platform Support & Licence
Desktop (Win/Mac/Linux)HDRP Supported
PC VR (SteamVR / OpenXR)HDRP Supported
Standalone VR (Quest / Pico)URP Supported
MobileNot Supported
ConsoleNo VR
LicenceGNU GPL v3 · Free
THE SDK ARCHITECTURE
Eight layers. Each with a clear responsibility and a clean boundary. Explore the runtime chain, known technical debt, and all key types below.
01
Data Authoring
LoveTriggerSOEnhancedLoveTriggerSO
LTSystem.Core
02
Lookup
LoveTriggerDatabase
LTSystem.Core
03
Runtime Request
LoveTriggerRequestLoveTriggerEvents
LTSystem.Core
04
Network / Consent
ILoveTriggerNetworkServiceNetworkedLoveTriggerManager
LTSystem.Network
05
Playback
UniversalAnimationControllerInteractableTimelineController
LTSystem.Animation
06
Scene Context
InteractableObjectNPCPartnerController
LTSystem.Interaction
07
Platform / Input
PlatformManagerUniversalInputSystem
LTSystem.Core
08
Player Lifecycle
PlayerConfigurationPlayerFactoryPlayerSpawnManager
LTSystem.Core
09
Bootstrap
LoveTriggerSystemManager
LTSystem.Core
A
SystemManager Initialization Bug
LoveTriggerSystemManager.cs
CRITICAL · ✓ FIXED

Premature yield break made IsInitialized = true unreachable. The system never fully initialized. Fixed by removing the premature yield break so the coroutine reaches completion.

Fix Applied
// WRONG — yield break kills the coroutine
yield break;
// IsInitialized = true was unreachable

// CORRECT — coroutine reaches completion
IsInitialized = true;
OnSystemInitialized?.Invoke();
B
Dual Platform Detection
PlatformDetectionSystem.cs + EnhancedPlatformDetectionSystem.cs
HIGH · ✓ RESOLVED

Two coexisting platform detection systems with diverging enums. Merged into single authoritative PlatformManager with unified Platform enum.

public enum Platform { Desktop, XR, Console, Mobile }
public static class PlatformManager {
    public static Platform Current { get; }
}
C
Network Consent Not Enforced
NetworkedLoveTriggerManager.cs
CRITICAL · ✓ IMPLEMENTED

Server-side path contained // TODO: actual consent logic. Consent structs existed but were not wired. Full async consent handshake now implemented and enforced at the network layer.

private async Task<bool> RequestConsentAsync(
    ulong targetPlayerRef,
    LoveTriggerRequest request,
    float timeoutSeconds = 15f) {
  // 1. Send ConsentRequestData RPC to target
  // 2. Await ConsentResponseData with timeout
  // 3. Return response.Accepted
  //    && response.RequestID == request.NetworkRequestID
}
D
InteractableObjectFix Reflection Hack
InteractableObjectFix.cs
MEDIUM · ✓ ELIMINATED

Reflection-based patch over private UI methods eliminated. SetupUIElements() is now protected virtual — subclasses override cleanly without reflection.

// Now protected virtual — override in subclasses
protected virtual void SetupUIElements() { }
// InteractableObjectFix.cs deleted entirely
E
Legacy Animation Path Divergence
LoveTriggerSO.cs
LOW · ✓ DEPRECATED

animatorClip marked [Obsolete]. AnimationData singleAnimation is now canonical. Legacy field retained for backwards compatibility only.

[HideInInspector]
[System.Obsolete("Use singleAnimation instead.")]
public AnimationClip animatorClip;

// Always use:
public AnimationData singleAnimation;
AnimationType
SingleCharacter
Partner
Synchronized
ConsentType
Manual
TrustedOnly
AlwaysAccept
TriggerPriority
Low
Normal
High
Critical
AnimationMethod
AnimatorOverride
PlayableGraph
SeparateAnimator
Code Standards
namespace LTSystem.Core { }
namespace LTSystem.Interaction { }
namespace LTSystem.Animation { }
namespace LTSystem.Network { }

/// <summary>XML doc on all classes and public methods</summary>
[Header("Section Name")]             // on all serialized field groups
Debug.Log("[ClassName] context: " + variable);

// Events
public UnityEvent<LoveTriggerRequest> OnTriggerExecuted;   // Inspector
public System.Action OnAnimationComplete;                   // Code-side

// Coroutine management
private Coroutine _currentSequence;
_currentSequence = StartCoroutine(PlayEncounter());
if (_currentSequence != null) { StopCoroutine(_currentSequence); _currentSequence = null; }
START BUILDING
Four paths depending on what you want to build. Start with the one that matches your goal.
STEP 01
Install the SDK
Clone or download the repository from GitHub. Copy Assets/LoveTriggerSDK/ into your Unity project's Assets/ directory.
git clone https://github.com/eroticissima/lovetriggersdk
// Copy Assets/LoveTriggerSDK/ → YourProject/Assets/LoveTriggerSDK/
STEP 02
Validate Your Setup
In Unity menu: Eroticissima > LoveTriggerSDK > Validate SDK Setup. Fix all warnings before proceeding.
STEP 03
Create a LoveTrigger Asset
Via Unity menu: Eroticissima > LoveTriggerSDK > Create New LoveTrigger. Fill in the Inspector.
triggerID        = "lt_kiss_soft"          // unique string identifier
displayName      = "Soft Kiss"             // shown in the selection UI
singleAnimation  // AnimationData — your clip + method + blend timing
consentType      = ConsentType.Manual      // for multiplayer
                 = ConsentType.AlwaysAccept // for solo / NPC
requiresConsent  = true                    // always, unless explicitly solo
STEP 04
Register in the Database
Place your LoveTriggerSO in Assets/Resources/LoveTriggers/. The database auto-loads on boot. No manual registration required.
STEP 05
Place an InteractableObject
Add InteractableObject to any scene GameObject. Assign your SO to Available Triggers. The full state machine runs automatically.
// Or drive it in code:
var trigger = LoveTriggerDatabase.Instance.Get("lt_kiss_soft");
interactableObject.InitiateTrigger(trigger, initiatorGO, partnerGO);
THE RULE
Always Use try/finally
BlendVRIKIn must always live inside a finally{} block. This guarantees VRIK is restored even if the sequence is interrupted — by the player, by a network disconnect, by any error.
IEnumerator BlendVRIKOut(VRIK vrik, float duration) {
    float elapsed = 0f;
    float start = vrik.solver.IKPositionWeight;
    while (elapsed < duration) {
        elapsed += Time.deltaTime;
        vrik.solver.IKPositionWeight =
            Mathf.Lerp(start, 0f, elapsed / duration);
        yield return null;
    }
    vrik.solver.IKPositionWeight = 0f;
}

IEnumerator BlendVRIKIn(
    VRIK vrik, float duration, float targetWeight = 1f) {
    float elapsed = 0f;
    float start = vrik.solver.IKPositionWeight;
    while (elapsed < duration) {
        elapsed += Time.deltaTime;
        vrik.solver.IKPositionWeight =
            Mathf.Lerp(start, targetWeight, elapsed / duration);
        yield return null;
    }
    vrik.solver.IKPositionWeight = targetWeight;
}

// USAGE — always try/finally
private IEnumerator PlaySequence(VRIK vrik) {
    try {
        yield return BlendVRIKOut(vrik, 0.4f);
        // your animation or Timeline sequence here
    }
    finally {
        // runs even on interruption — no exceptions
        yield return BlendVRIKIn(vrik, 0.4f);
    }
}
OVERVIEW
Dynamic Track Binding
Name your Timeline tracks "Source" and "Target". The controller binds the correct avatars at runtime. No hardcoded scene references in your Timeline asset.
private void BindCharacterTracks(
    PlayableDirector director,
    GameObject source, GameObject target) {

    foreach (var binding in director.playableAsset.outputs) {
        if (binding.streamName.Contains("Source"))
            director.SetGenericBinding(binding.sourceObject, source);
        if (binding.streamName.Contains("Target"))
            director.SetGenericBinding(binding.sourceObject, target);
    }
}
VCAM PRIORITY
Cinemachine Priority Pattern
Encounter VCam gets priority 15. Default gameplay camera = 10. Destroy on sequence end — always inside finally{}.
// Spawn encounter VCam with higher priority
spawnedVCam = Instantiate(trigger.vcamPrefab, transform)
    .GetComponent<CinemachineVirtualCamera>();
spawnedVCam.Priority = trigger.vcamPriority; // 15

// In finally{} — gameplay VCam regains control automatically
Destroy(spawnedVCam.gameObject);
CONFIGURATION
Inspector Setup
NPCPartnerController runs through the same consent pipeline as a human player. AlwaysAccept simply shortens the hesitation arc. There is no bypass.
[Header("Consent Behavior")]
ConsentType _consentBehavior = ConsentType.Manual;

[Range(0f, 1f)]
float _agreeProbability = 0.85f; // for Manual type

// Hesitation arc — lerped by relationship score
float _thinkDurationMin = 0.5f;
float _thinkDurationMax = 2.0f;

// Relationship score 0–100
// +10 per completed encounter / shorter hesitation at higher scores
float _relationshipScore = 0f;

// Audio banks — keyed to ConsentType, not random
AudioClip[] _greetingClips;
AudioClip[] _agreementClips;
AudioClip[] _declineClips;
CONSENT ARC
How the NPC Responds
The NPC subscribes to the event bus on Awake(). Consent request arrives → Think() → Agree() → ApproachInitiator() → Execute(). Same state machine. No bypass.
// NPC subscribes to consent requests automatically on Awake()
LoveTriggerEventBus.OnConsentRequestReceived
    += HandleConsentRequest;

// Response published through the same event bus
LoveTriggerEventBus.RaiseConsentResponseReceived(
    new ConsentResponseData {
        RequestID          = requestData.RequestID,
        Accepted           = accepted,
        ResponderPlayerRef = config.networkPlayerRef
    });
WHAT EXISTS · WHAT IS COMING
✓ Available Now
  • README.md: full architecture overview, layer reference, quick start, debt register
  • This page: getting started guides, code examples, consent architecture walkthrough
  • Interactive architecture dashboard above
  • Inline XML docs on all public classes — partial, expanding each commit
◎ Coming Soon
  • Full API reference: auto-generated from inline XML docs
  • Video walkthroughs: LoveTrigger authoring, Timeline setup, multiplayer config
  • DAZ → Unity pipeline guide for HAVAS and avatar content creators
  • Avatar customization deep dive: body config, genital attachment, material variants
◈ Contribute
  • Documentation is open source alongside the code
  • Found something missing or wrong? Open an issue or submit a PR
  • The best documentation is written by the people who actually use the thing
  • → github.com/eroticissima

THE SDK IS FREE.
THE COMMUNITY IS OPEN.
THE DOOR IS HERE.

Everything you need to start building is available right now. What you build with it is yours.

GitHub

Full source · README · issue tracker · PRs welcome

→ github.com/eroticissima
Discord

Technical discussion · onboarding · direct SDK access

→ discord.gg/KTCdKNnvGb
Patreon

Sugar Creators get direct technical onboarding from Miyö · €10/month

→ patreon.com/eroticissima