// SPDX-License-Identifier: MIT // Copyright (c) 2026 Incoprea // Paired animation layer preview // Not compiled or tested in-world // Setup: Add licensed animations upper_layer and lower_layer that were designed to affect different joints. Owner-touch grants permission. // Stop / restore: Touch while playing or wait five seconds. Stop Animating Me is the fallback after interruption. // Notes: Stop before renaming or removing animation assets. An animation asset may also be used by another controller: do not run competing controllers for the same asset. LSL does not change animation priority or joint masks; those must be authored in the assets. This is a compatibility preview, not a universal animation blender. // License: see LICENSE in this distribution. // Original Incoprea. MIT. Not compiled or tested in-world. integer pending; integer playing; integer permitted() { return (llGetPermissions()&PERMISSION_TRIGGER_ANIMATION)&&llGetPermissionsKey()==llGetOwner(); } stop() { if(playing&&permitted()) { llStopAnimation("upper_layer"); llStopAnimation("lower_layer"); } playing=FALSE; llSetTimerEvent(0.0); } default { touch_start(integer n) { if(llDetectedKey(0)!=llGetOwner())return; if(playing) { stop(); return; } if(pending)return; if(llGetInventoryType("upper_layer")!=INVENTORY_ANIMATION||llGetInventoryType("lower_layer")!=INVENTORY_ANIMATION) { llOwnerSay("Add upper_layer and lower_layer animations."); return; } pending=TRUE; llRequestPermissions(llGetOwner(),PERMISSION_TRIGGER_ANIMATION); } run_time_permissions(integer p) { if(!pending)return; pending=FALSE; if(!permitted())return; if(llGetInventoryType("upper_layer")!=INVENTORY_ANIMATION||llGetInventoryType("lower_layer")!=INVENTORY_ANIMATION)return; playing=TRUE; llStartAnimation("upper_layer"); llStartAnimation("lower_layer"); llSetTimerEvent(5.0); } timer() { stop(); } changed(integer change) { if(change&CHANGED_OWNER)llResetScript(); } }