Retargeting Mixamo In-Place Animation To Epic Skeleton

If you get them via torrent, you don’t have a valid license for them as you are not allowed to share/download them from 3rd party sources. Fastest legit way of getting them all is not that fast but is what I do myself. Just browse through all anims (there are 2400+) and add them individually to your own collection. One collection can hold up to 75 anims so you’ll end up with 33 collections.

Do note that if you want to later on change the character/skeleton from the collection, you can do that by changing the char and then do something with the collection name so it lets you resave it (I usually just add space and delete space for that).

Once you have the collections, you can download them again with various export settings.

This is a completely wrong way of thinking about it. If something is free, it doesn’t automatically mean there’s no license (and there is in this case). What you are practically suggesting here is that it would ok to pirate assets that Abode holds all rights to.

People, same things apply to everything you can get for free. If there’s license, you have to go with it’s terms if you want to use it yourself, price has ZERO influence on this. For example, if you get free asset from Unreal Marketplace or you get free asset from Unity Asset Store, Marketplace/Asset Store terms apply just the same way as you had paid $100 for it (unless they have separately mentioned different terms).

As my last point on this subject, talking about piracy is not allowed on these forums, so do think carefully before suggesting people could do this.

OK this is for animation but how to add a fuse character to epic skeleton?

Thank You so much for this tutorial! I know nothing of Maya and could not even remove the root from the skeleton myself. thanks to You I already processed 300 animations and can continue my study and work :slight_smile:

I guess you can use the animation and rigging toolkit for maya-I havent tried it
or
retarget inside unreal, but you have to create a rig in retarget manager which includes matching all the bone names (root remain none). I found this maxscript on mixamo forums which I guess renames the bones. I don’t have max, but it’s good for bone reference:

$‘mixamorig:Hips’.name=“pelvis”
$‘mixamorig:Spine’.name=“spine_01”
$‘mixamorig:Spine1’.name=“spine_02”
$‘mixamorig:Spine2’.name=“spine_03”
$‘mixamorig:Neck’.name=“neck_01”
$‘mixamorig:Head’.name=“head”
–$‘mixamorig:HeadTop_End’.name=“”
$‘mixamorig:LeftShoulder’.name=“clavicle_l”
$‘mixamorig:LeftArm’.name=“upperarm_l”
$‘mixamorig:LeftForeArm’.name=“lowerarm_l”
$‘mixamorig:LeftHand’.name=“hand_l”

$‘mixamorig:LeftHandThumb1’.name=“thumb_01_l”
$‘mixamorig:LeftHandThumb2’.name=“thumb_02_l”
$‘mixamorig:LeftHandThumb3’.name=“thumb_03_l”
–$‘mixamorig:LeftHandThumb4’.name=“”
$‘mixamorig:LeftHandIndex1’.name=“index_01_l”
$‘mixamorig:LeftHandIndex2’.name=“index_02_l”
$‘mixamorig:LeftHandIndex3’.name=“index_03_l”
–$‘mixamorig:LeftHandIndex4’.name=“”
$‘mixamorig:LeftHandMiddle1’.name=“middle_01_l”
$‘mixamorig:LeftHandMiddle2’.name=“middle_02_l”
$‘mixamorig:LeftHandMiddle3’.name=“middle_03_l”
–$‘mixamorig:LeftHandMiddle4’.name=“”
$‘mixamorig:LeftHandRing1’.name=“ring_01_l”
$‘mixamorig:LeftHandRing2’.name=“ring_02_l”
$‘mixamorig:LeftHandRing3’.name=“ring_03_l”
–$‘mixamorig:LeftHandRing4’.name=“”
$‘mixamorig:LeftHandPinky1’.name=“pinky_01_l”
$‘mixamorig:LeftHandPinky2’.name=“pinky_02_l”
$‘mixamorig:LeftHandPinky3’.name=“pinky_03_l”
–$‘mixamorig:LeftHandPinky4’.name=“”
$‘mixamorig:RightShoulder’.name=“clavicle_r”
$‘mixamorig:RightArm’.name=“upperarm_r”
$‘mixamorig:RightForeArm’.name=“lowerarm_r”
$‘mixamorig:RightHand’.name=“hand_r”

$‘mixamorig:RightHandThumb1’.name=“thumb_01_r”
$‘mixamorig:RightHandThumb2’.name=“thumb_02_r”
$‘mixamorig:RightHandThumb3’.name=“thumb_03_r”
–$‘mixamorig:RightHandThumb4’.name=“”
$‘mixamorig:RightHandIndex1’.name=“index_01_r”
$‘mixamorig:RightHandIndex2’.name=“index_02_r”
$‘mixamorig:RightHandIndex3’.name=“index_03_r”
–$‘mixamorig:RightHandIndex4’.name=“”
$‘mixamorig:RightHandMiddle1’.name=“middle_01_r”
$‘mixamorig:RightHandMiddle2’.name=“middle_02_r”
$‘mixamorig:RightHandMiddle3’.name=“middle_03_r”
–$‘mixamorig:RightHandMiddle4’.name=“”
$‘mixamorig:RightHandRing1’.name=“ring_01_r”
$‘mixamorig:RightHandRing2’.name=“ring_02_r”
$‘mixamorig:RightHandRing3’.name=“ring_03_r”
–$‘mixamorig:RightHandRing4’.name=“”
$‘mixamorig:RightHandPinky1’.name=“pinky_01_r”
$‘mixamorig:RightHandPinky2’.name=“pinky_02_r”
$‘mixamorig:RightHandPinky3’.name=“pinky_03_r”
–$‘mixamorig:RightHandPinky4’.name=“”

$‘mixamorig:LeftUpLeg’.name=“thigh_l”
$‘mixamorig:LeftLeg’.name=“calf_l”
$‘mixamorig:LeftFoot’.name=“foot_l”
$‘mixamorig:LeftToeBase’.name=“ball_l”
–$‘mixamorig:LeftToe_End’.name=“”

$‘mixamorig:RightUpLeg’.name=“thigh_r”
$‘mixamorig:RightLeg’.name=“calf_r”
$‘mixamorig:RightFoot’.name=“foot_r”
$‘mixamorig:RightToeBase’.name=“ball_r”
–$‘mixamorig:RightToe_End’.name=“”

root = bone()

root.name=“root”

$‘pelvis’.parent = root

could there be a script for blender maybe?

There’s also a list with UE4<>Mixamo bone names in the animation retargeting doc:
https://docs.unrealengine.com/latest/INT/Engine/Animation/RetargetingDifferentSkeletons/

Can someone make a tutorial for this fix, but in blender?

The most convenient way would be a browser console script that goes through the 2400+ animations and adds them to your assets. Of course that is only reasonable as a backup of sorts (say, Mixamo drops the service with no prior notice …as they did with the UE4 format), otherwise the best way is to work with the site’s search and customization options.

It just so happens I’m working on such a script right now.
In the first pass it goes through all animations and adds them to your assets,
then in a second pass it creates packs, 75 anims each and auto-sets checkmarks for “mirror” and / or “in place” according to your preferences.
It basically remedies the site’s lack of multi selection options.
All you have to do then, is go into “My Assets” and download the packs.

Hope such a script doesn’t violate any ToS, but I can’t imagine how it could.

You’d need to ignore the collections somehow as they show up amongs regular anims (unless you can somehow set mixamo not to show them). As far as I know, collections anims are still in the full list so they’d be just duplicates anyway.

Since the no-root skeleton is provided here, there is no need to use any other software, just upload it to mixamo and download the animation with it.
One thing for Blender users: If you also use the ue4 tools and its mannequin I noticed that i cannot directly retarget the no-root/mixamo animations to the blender skeleton, because it will be rotated. however I can retarget it to the regular mannequin, then that animation to the blender mannequin and it works.

I wouldn’t be suprised…

Yes, I’m reading the animation name and ignoring items if they contain the substring " pack" (hopefully there are no false positives, but I’ll check).

Only thing I haven’t figured out, is renaming the pack - I am able to change the text input, but the site only applies that change on actual key- or mouse press.

Keep Workaround 8). Good luck

Edit: after Adobe changed the Mixamo site and services, the script in this post is outdated. To get a revised script, follow this link: Mixamo Download Script

Original Message: Ok, here’s my script.

What it does: It goes through the Mixamo store and gathers all 2446 animations in packs, 75 each.
You can set it up to change the animation properties inside the packs (“in Place” and “Mirrored”)
It can also add the animations to “My Assets”, but that requires a second go through and is not really necessary (in Mixamo you can select your packs and click “Add to My Assets” once for each pack - which takes ~1 minute, whereas the script on the other hand would need about 20 minutes to click through all 2k+ anims).

How To

  1. copy the script below into a text file
  2. edit the settings (see below)
  3. open your browser’s console (Chrome: shift+ctrl+J, Firefox: shift+ctrl+K)
  4. copy the content of the script and paste it into the console, hit Enter
  5. wait until it finishes … it takes quite a while (there’s over 2400 items to select, each requires several clicks, each click causes the site to reload the animation data, etc.)
  6. once done, go to My Assets -> Animations
  7. (optional) click on each pack, rename it if you want, click “Add To My Assets” if it doesn’t say “You own this”
  8. click the check marks on all the packs you want to download, click Queue Download and set your preferences
  9. download from My Assets -> Downloads (use a browser extension such as “uSelect iDownload” if you don’t feel like clicking on each item individually)
  10. all done

Settings
The script has a couple of variables that can be customized, all are commented.
The main ones are “setupStateMirror” and “setupStateInPlace”. Those will determine the animation settings.

Manual renaming
If you want your packs to be neatly organized set “setupAllowManualPackSave” to true.
This will pop up a message box after each page finishes (you will receive a sound notification, too) and you’ll then have 5 seconds to click on the text field with the pack name (it will already read something like “P1_Mirror_inPlace”) - just click on it + hit Enter, that’s all.
Disable this option, if you want the script to run uninterrupted till the end, but you will end up with all packs named “In-Progress”.
(I wanted this to take place automatically, but wasn’t able to make the site acknowledge the change without an actual click / keypress – if someone has a solution how to simulate that, I’d be delighted)

Also worth noting, if the script encounters too many problems on a given page (e.g. sometimes an animation can get stuck and won’t finish loading) it will reload the page on it’s own and retry. This results in an unfinished pack in your assets - it is not a problem, but keep that in mind in case you end up with 35 packs instead of 33.

I think that’s all… if you run into problems or the script does weird stuff, hit me with the console log on PM.


////////////////////////////////
// for best performance, change settings on mixamo.com to small non-animated thumbnails and 96 anims per page
// open browser developer console (Chrome: ctrl+shift+J, FireFox: ctrl+shift+K )
// and paste contents of this file
////////////////////////////////

// mode
var setupMode               = 1;   // 0:Add To Assets; 1:Add To Packs;
// 0 will hit "Add to Assets" for each anim, 1 will manage packs

// Packs
var setupStateMirror                = false;  // sets "mirror" to true or false
var setupStateInPlace               = false;  // sets "in place" to true or false
var setupPackSize                   = "75";  // size of packs - max is 75 (recommended)

// Timers ( 1000 = 1 second) - increase if script runs into problems, or decrease to try to speed up
var setupGlobalTimeOffset       = 100;   // all timers will be increased by x (increase if script has to retry often)
var setupTimeModifier           = 0.1;   // all timers will multiply by x (increase if script has to retry often)

// Prompts, Alerts
var setupPromptOnEndOfPage = false;   // popup with summary after each page
var setupAllowManualPackSave = false;   // will halt script to allow renaming of pack
var setupManualSavePrompt2 = false; // a second prompt to allow more time for renaming
var setupTimeManualName = 5000;   // delay when prompted to rename pack (can be changed in the prompt later on)
var setupPromptOnException = false; // will display alert when a page has to be reloaded due to too many delays

// Audio Notifications
var setupPlaySounds         = true;  // play sound notifications
var setupBeepOnPage         = true;  // notification when changing page
var setupBeepOnAdd          = false; // notification when an animation has been added to assets
var setupBeepOnFinish       = true;  // notification when script has finished
var setupBeepOnRetry = true;  // notifies when script couldn't process current animation, it will attempt to retry
var setupBeepOnPrompts = true;  // notify on alert windows

////////////////////////////////
// Debug
////////////////////////////////

var debugMaxAttempts     = 0;     // will stop after x anims, 0 = unlimited
var debugVerbose       = true;  // write messages to console

////////////////////////////////
// Don't edit below
// Captions and Classes in mixamo code - if somethings stops workingn, possibly site has been changed
////////////////////////////////

var pageURL                         = "https://www.mixamo.com/store/#/search?type=Motion%252CMotionPack";
var setupElementID_Products         = "product";
var setupElementID_AddToAssets      = ".addtocart";
var setupElementID_InPlace          = "inplace";
var setupElementID_Mirror           = "mirror";
var setupElementID_ViewDownload     = "View / Download";
var setupElementID_AddToCartCaption = "Add to My Assets";
var setupElementID_PackName = "form-control editable-text";
var setupQueueButtonClass       = "pull-right btn btn-primary";
var setupQueueButtonCaption     = "Queue Download";
var setupStartDownloadButtonClass   = "btn btn-primary";
var setupStartDownloadButtonCaption = "Queue Download";
var setupDlSettingsDropBoxClass = "input-sm form-control";
var setupAddToPackButtonClass       = "btn-block btn btn-default";
var setupInPackButtonClass = "list-group-item animation-pack-animation";
var setupInPackButtonClassActive = "list-group-item animation-pack-animation active-animation";
var setupElementID_AddToAssets      = ".addtocart";
var setupElementID_PackName = "form-control editable-text";
var setupElementID_SavePack = "fa fa-save fa-fw";
var setupElementID_DeletePack = "fa fa-times fa-fw";

////////////////////////////////
var setupAlignPageLimitWithPackSize = true;  // when true, will force "anims per page" to setupPackSize
var setupSavePacks                  = true;  // will click "save"
var setupRenamePacks = true; // doesn't really wort atm
var index   = 0;
var skipped = 0;
var items   = document.getElementsByClassName( setupElementID_Products );
var button  = document.querySelector( setupElementID_AddToAssets );
////////////////////////////////
var debugFailedStart   = 0;
var numAssetsAdded = 0;
var numAssetsAddedCurrPage  = 0;
var numInAssetsCurrPage = 0;
var numInAssetsTotal = 0;
var scriptPaused       = true;
var debugNoPageTurn   = false;
////////////////////////////////
var numPacks         = 0;
var numInPacksTotal   = 0;
var numSkippedTotal = 0;
var numInCurrentPack = 0;
var numInCurrentPackAttempted = 0;
var numInPacksTotalAttempted = 0;
var timeEnd = 0, timeStart = 0;
////////////////////////////////
var pageNum       = geUrlPageNum();
var pageMax     = 0;

////////////////////////////////

setupAddToAssets = (setupMode === 0);
if (setupPackSize > "75") setupPackSize = "75";
if (setupAddToAssets) setupAlignPageLimitWithPackSize = false;

if (!audioCtx) var audioCtx = new (window.AudioContext || window.webkitAudioContext || window.audioContext);
function beep(duration, frequency, volume, type, callback) {
if (!setupPlaySounds)  return;

    var oscillator = audioCtx.createOscillator();
    var gainNode = audioCtx.createGain();

    oscillator.connect(gainNode);
    gainNode.connect(audioCtx.destination);

    if (volume){gainNode.gain.value = volume;};
    if (frequency){oscillator.frequency.value = frequency;}
    if (type){oscillator.type = type;}
    if (callback){oscillator.onended = callback;}

    oscillator.start();
    setTimeout(function(){oscillator.stop()}, (duration ? duration : 500));
}

function timeMod( baseTime ){
var t = ((baseTime)*setupTimeModifier) + setupGlobalTimeOffset;
if (t < baseTime*0.1) t = baseTime*0.1;
if (t > baseTime*10) t = baseTime*10;
return t;
}

function getUrlVars() {
var vars = {};
var parts = window.location.href.replace(/?&]+(^=&]+)=(^&]*)/gi,    
function(m,key,value) {
vars[key] = value;
});
return vars;
}

function geUrlLimit(){
var result = getUrlVars()"limit"];
if (result && debugVerbose) console.log(result);
else {
if (debugVerbose) console.log("[DEBUG] geUrlLimit :: param LIMIT not found.");
result = "96";
}
return result;
}

function geUrlPageNum(){
var result = getUrlVars()"page"];
if (result && debugVerbose) console.log(result);
else {
if (debugVerbose) console.log("[DEBUG]param PAGE not found.");
result = 1;
}
return result;
}


var pageLimit   = geUrlLimit();
function validateUrl(){
if (setupAlignPageLimitWithPackSize) {
if (pageLimit != setupPackSize) {
pageLimit = setupPackSize;
pageNum = 1;
reloadPage();

return false;
}
}
return true;
}

function mixamoScript(){
timeStart = Date.now();

if (debugVerbose) console.log("[DEBUG] mixamoScript :: Start; index:",index);
var pagination = document.querySelector(".pagination li:nth-last-child(2) a");
if (pagination) pageMax       = parseInt(pagination.textContent, 10);
else pageMax       = 1;
scriptPaused       = false;
items  = document.getElementsByClassName( setupElementID_Products );

numInCurrentPack = 0;
numInCurrentPackAttempted = 0;
index = 0;
skipped   = 0;
numInAssetsCurrPage     = 0;
numAssetsAddedCurrPage   = 0;


// get products or retry later
if (items.length == 0) {
++debugFailedStart;
if (debugFailedStart > 2) {
reloadPage();
return;
}
setTimeout(mixamoScript, timeMod(2000));
return;
}
debugFailedStart = 0;

// process first element
if (setupAddToAssets)
nextElementToAssets();
else nextElementToPack();
}

function onNextElement() {
if (debugVerbose) console.log("[DEBUG] onNextElement :: start; index:",index);

if (!items || items.length == 0) {
if (debugVerbose) console.log("[DEBUG] onNextElement :: items; index:",index);
items = document.getElementsByClassName( setupElementID_Products );
}
if (!button) {
if (debugVerbose) console.log("[DEBUG] onNextElement :: button; index:",index);
button = document.querySelector( setupElementID_AddToAssets );
}
if (items.length != 0) {
// Next Page
if(index >= items.length) {
// end of page
onEndOfPage();
return true;
}
items[index].click();

if (debugVerbose) console.log("[DEBUG] onNextElement :: Clicked");
return true;
}

return false;
}

var buttonClicked = 0;
function nextElementToAssets() {
if (debugVerbose) console.log("[DEBUG] nextElementToAssets :: start; index:",index);

if (debugMaxAttempts > 0 && index >= debugMaxAttempts) {
if (debugVerbose) console.log("[DEBUG] nextElementToAssets :: debugMaxAttempts:",debugMaxAttempts,"; onFinish");
onFinish();
return;
}

if ( !onNextElement() ) {
// retry
setTimeout(nextElementToAssets, timeMod(1000) );
if (debugVerbose) console.log("[DEBUG] nextElementToAssets :: !onNextElement");
return false;
}
if ( scriptPaused ) return;

retryCounter = 0;

setTimeout(addToMyAssets, timeMod( 500 ) );
if (debugVerbose) console.log("[DEBUG] nextElementToAssets :: End");
}

function handleRetries(){
++retryCounter;
if (debugVerbose) console.log("[DEBUG] handleRetries :: retryCounter:",retryCounter);
if (retryCounter > 10) {
if (setupPromptOnException){
if (setupBeepOnPrompts) beepWarning();
alert("Retries exceeded treshold, reloading page");
}
reloadPage();
if (debugVerbose) console.log("[DEBUG] handleRetries :: button.textContent:",button.textContent,"; index:",index,"; retryCounter:",retryCounter);
return false;
}
if (retryCounter > 5) {
setTimeout(nextElementToAssets, timeMod(0));
if (debugVerbose) console.log("[DEBUG] handleRetries :: button.textContent:",button.textContent,"; index:",index,"; retryCounter:",retryCounter);
return false;
}
return true;
}

var retryCounter = 0;
function addToMyAssets() {
if (debugVerbose) console.log("[DEBUG] addToMyAssets :: Start; Index:",index);

// main button is disabled (loading or adding)
if ( buttonDisabled() || isAnimLoading()) {
if (debugVerbose) console.log("[DEBUG] addToMyAssets :: main button Disabled ...retry; index:",index);
if (!handleTimeout() ) return;
setTimeout(addToMyAssets, timeMod(250));
return;
}
resetTimeout();

if (!handleRetries()) return;
if (retryCounter <= 1) {
setTimeout(addToMyAssets, timeMod(250));
return;
}


var currAnim = getAnimName();
if (debugVerbose) console.log("[DEBUG] addToMyAssets :: Anim: ",currAnim,"; index:",index);

if (isAnimPack()===true) {
if (debugVerbose) console.log("[DEBUG] addToMyAssets :: Anim Pack ...skip; index:",index);
++skipped;
addToIgnored( currAnim );
incIndex();
setTimeout(nextElementToAssets, timeMod(100));

return;
}

// main button indicates that asset already is owned)
if (button.textContent == setupElementID_ViewDownload) {
if (buttonClicked == 0)
addToCurrItems( currAnim + " (Already In Assets)" );
else addToCurrItems( currAnim + " (Added)" );

incIndex();
++numInAssetsCurrPage;


setTimeout(nextElementToAssets, 100);
if (debugVerbose) console.log("[DEBUG] addToMyAssets :: button.textContent:",button.textContent,"; new index:",index,"; setTimeout(nextElementToAssets, 250)");
return;
}

// main button is ready to add asset)
if (button.textContent == setupElementID_AddToCartCaption) {
if (buttonClicked == 0) {
button.click();

++buttonClicked;
++numAssetsAddedCurrPage;
if (setupBeepOnAdd) beepOnAdd();

setTimeout( nextElementToAssets, 0);
if (debugVerbose) console.log("[DEBUG] addToMyAssets :: Added To Assets; buttonClicked:",buttonClicked);
return;
} else {
// don't click if already clicked
++buttonClicked;
if (buttonClicked > 5) buttonClicked = 0;
setTimeout(addToMyAssets, timeMod(250));
if (debugVerbose) console.log("[DEBUG] addToMyAssets :: AddToAssets.click attempted ",buttonClicked," times; button.textContent:",button.textContent,"; numAssetsAdded:",numAssetsAdded,"; setTimeout(addToMyAssets, 250)");
return;
}
} else { // main button caption is something unexpectedpromp

setTimeout(addToMyAssets, timeMod(250));
if (debugVerbose) console.log("[DEBUG] addToMyAssets :: button.textContent:",button.textContent,"; setTimeout(addToMyAssets, 250)");
return;
}
if (debugVerbose) console.log("[DEBUG] addToMyAssets :: end");
}

function diffAnimsInPack(){
if (debugVerbose) console.log("[DEBUG] diffAnimsInPack :: Start; index:",index);
var diff = numAnimsInPack() - (index - skipped);
if (debugVerbose) console.log("[DEBUG] diffAnimsInPack :: diff:",diff);

return diff;
}

function buttonDisabled(){
if (debugVerbose) console.log("[DEBUG] buttonDisabled :: Start; index:",index);

var result = (button && button.disabled == true);
if (!button) console.log("[DEBUG] buttonDisabled :: button == null; index:",index);



return result;
}

function canSelectInPack(){
if (debugVerbose) console.log("[DEBUG] canSelectInPack :: Start; index:",index);
// var items = document.getElementsByClassName( setupInPackButtonClass );

// 0 == not yet added; 1 == added
if (diffAnimsInPack() !== 1) {
if (debugVerbose) console.log("[DEBUG] canSelectInPack :: False; diffAnimsInPack():",diffAnimsInPack(),"; index:",index);

return false;
}
return true;
}

function obsolete() {
if (!items || items.length<=0) {
if (items) console.log("[DEBUG] canSelectInPack :: False; items.length:",items.length,"; index:",index);
else if (debugVerbose) console.log("[DEBUG] canSelectInPack :: False; items:]; index:",index);

return false;
} else {
var nameInPack = items[0].textContent;
var animName   = getAnimName();

if (nameInPack === animName) {
if (debugVerbose) console.log("[DEBUG] canSelectInPack :: True; index:",index);

return true;
} else {
if (debugVerbose) console.log("[DEBUG] canSelectInPack :: False; names don't match; index:",index);

return false;
}
}
}

function selectInPack(){
if (debugVerbose) console.log("[DEBUG] selectInPack :: Start; index:",index);

if (!canSelectInPack()) {
if (debugVerbose) console.log("[DEBUG] selectInPack :: False; canSelectInPack() false; index:",index);
return false;
}

var items = document.getElementsByClassName( setupInPackButtonClassActive );
if (!items || items.length <= 0) {
if (debugVerbose) console.log("[DEBUG] selectInPack :: False; No item to click; index:",index);
return false;
}

var nameInPack = items[0].textContent;
var animName   = getAnimName();

if (nameInPack.toLowerCase() === animName.toLowerCase()) {
items[0].click();
if (debugVerbose) console.log("[DEBUG] selectInPack :: True");
return true;
} else alert("[Critical Error] index:"+index+"
Anim Names do not match!
Name in Pack:"+nameInPack+" vs Current Anim:"+animName);

return false;
}

function validateVariations() {
if (debugVerbose) console.log("[DEBUG] validateVariations :: Start; index:",index);

if (hasElement(setupElementID_Mirror))
if (setupStateMirror !== isChecked( setupElementID_Mirror )){
if (debugVerbose) console.log("[DEBUG] validateVariations :: Failed; setupStateMirror:",setupStateMirror,"; isChecked( ",setupElementID_Mirror," ):",isChecked( setupElementID_Mirror ) );
return false;
}

if (hasElement(setupElementID_InPlace))
if (setupStateInPlace != isChecked( setupElementID_InPlace )) {
if (debugVerbose) console.log("[DEBUG] validateVariations :: Failed; setupStateInPlace:",setupStateInPlace,"; isChecked( ",setupElementID_InPlace," ):",isChecked( setupElementID_InPlace ) );
return false;
}

if (debugVerbose) console.log("[DEBUG] validateVariations :: End");
return true;
}

function isAnimPack(){
var str = getAnimName();
str = str.toLowerCase();
var n = str.search(" pack");
return ( n > -1 );
}

function isAnimLoading(){
var str = getAnimName();
str = str.toLowerCase();
var n = str.search("loading...");
return ( n > -1 );
}

function getAnimName(){
if (debugVerbose) console.log("[DEBUG] getAnimName :: Start; index:",index);
var element = document.getElementsByClassName( "text-center h5" );
if (element && element.length>0) {
if (debugVerbose) console.log("[DEBUG] getAnimName :: name:",element[0].textContent,"; Start; index:",index);
return element[0].textContent;
}
if (debugVerbose) console.log("[DEBUG] getAnimName :: Failed; Start; index:",index);
return "]";
}

var debugStatusString = "";
function printStatus() {
if (debugVerbose) {
console.log("[DEBUG] --------- printStatus :: Start; index:",index);
console.log("[DEBUG] --------- printStatus :: numPacks:",numPacks);
console.log("[DEBUG] --------- printStatus :: numInPacksTotal:",numInPacksTotal);
console.log("[DEBUG] --------- printStatus :: numInCurrentPack:",numInCurrentPack);
console.log("[DEBUG] --------- printStatus :: numInCurrentPackAttempted:",numInCurrentPackAttempted);
console.log("[DEBUG] --------- printStatus :: numInPacksTotalAttempted:",numInPacksTotalAttempted);
}
}

function printStatusAsString() {
var txt =
"Last Index: "+index+"
"+
"
"+numPacks+" Packs Saved"+
"
"+(numInCurrentPack)+" Anims In Current Pack (skipped: "+skipped+")"+
"
"+(numInPacksTotal)+" Anims In All Packs (skipped: "+numSkippedTotal+")"+
"

Skipped / Collections:
"+
printIgnored();

return txt;
}

var maxRetries = 0;
var debugRetries = -1;
var numClickedAddToPack = 0;

function nextElementToPack() {
if (debugVerbose) console.log("[DEBUG] nextElementToPack :: Start; index:",index);

if (debugMaxAttempts > 0 && index >= debugMaxAttempts) {
if (debugVerbose) console.log("[DEBUG] nextElementToPack :: debugMaxAttempts:",debugMaxAttempts,"; onFinish");
onFinish();
return;
}

if (index==0) deletePack();

if ( !onNextElement() ) {
setTimeout(nextElementToPack, timeMod(250));
if (debugVerbose) console.log("[DEBUG :: WARNING] nextElementToPack :: !onNextElement; scriptPaused:",scriptPaused);
return false;
}
if ( scriptPaused ) {
if (debugVerbose) console.log("[DEBUG] nextElementToPack :: scriptPaused");
return;
}
numClickedAddToPack=0;
addCurrentElement_ToPack_f = true;

setTimeout(startElement_a, timeMod( 0 ));
if (debugVerbose) console.log("[DEBUG] nextElementToPack :: End");
}

function startElement_a(){
if (debugVerbose) console.log("[DEBUG] startElement_a :: called by nextElementToPack; index:",index);
addCurrentElement_ToPack();
}

function startElement_b(){
if (debugVerbose) console.log("[DEBUG] startElement_b :: called by addCurrentElement_ToPack; index:",index);
addCurrentElement_ToPack();
}

function startElement_c(){
if (debugVerbose) console.log("[DEBUG] startElement_c :: called by afterAddToPack; index:",index);
addCurrentElement_ToPack();
}

var addCurrentElement_ToPack_f = true;
function addCurrentElement_ToPack(){
if (debugVerbose) console.log("[DEBUG] addCurrentElement_ToPack :: Start; index:",index);

printStatus();

var a = isAnimLoading();
var b = buttonDisabled();
if ( b || a ){
if (debugVerbose && b) console.log("[DEBUG] addCurrentElement_ToPack :: main button Disabled; index:",index);
if (debugVerbose && a) console.log("[DEBUG] addCurrentElement_ToPack :: anim loading; index:",index);
if (!handleTimeout() ) return false;

setTimeout(startElement_b, timeMod(250)); //setupDelay
return false;
}
resetTimeout();

if (addCurrentElement_ToPack_f) {
setTimeout(addCurrentElement_ToPack, timeMod(100));
addCurrentElement_ToPack_f = false;
return;
}

++debugRetries;
if (debugVerbose) console.log("[DEBUG] addCurrentElement_ToPack :: debugRetries:",debugRetries);

if (debugRetries > maxRetries) maxRetries = debugRetries;
if (debugRetries > 10) {
//updateStatus();
var txt = "Retries exceeded treshold, reloading page!";
txt += "

OK to continue.";
txt += "


maxRetries: "+(maxRetries-1)+"
debugRetries: "+debugRetries+"
Index: "+index;

var r = true;
if (setupPromptOnException) {
if (setupBeepOnPrompts) beepWarning();
r = confirm( txt );
}

if (r !== true) {
savepack();
return false;
}
debugRetries = -1;
reloadPage();
return false;
} else if (debugRetries > 5) {
setTimeout(nextElementToPack, timeMod(100));
return false;
}

if (isAnimPack()===true) {
if (debugVerbose) console.log("[DEBUG] addCurrentElement_ToPack :: Anim Pack ...skip; index:",index);
++skipped;
addToIgnored( getAnimName() );
incIndex();
setTimeout(nextElementToPack, timeMod(0));
return false;
}

setTimeout( addCurrentElement_ToPack_a, timeMod(250)); //setupDelay
}

function addCurrentElement_ToPack_a(){
if (debugVerbose) console.log("[DEBUG] addCurrentElement_ToPack_a :: Start; AnimName:",getAnimName(),"index:",index);

if ( buttonDisabled() || isAnimLoading() ){
if (debugVerbose) console.log("[DEBUG] addCurrentElement_ToPack_a :: main button Disabled ...retry; index:",index);
if (!handleTimeout() ) return false;

setTimeout(addCurrentElement_ToPack_a, timeMod(250));
return false;
}
resetTimeout();

if (!canSelectInPack()) addToPack();

setTimeout( addCurrentElement_ToPack_b, timeMod(250)); //setupDelay
if (debugVerbose) console.log("[DEBUG] addCurrentElement_ToPack_a :: End; index:",index);
}

var debugRetries_b = 0;
function addCurrentElement_ToPack_b(){
if (debugVerbose) console.log("[DEBUG] addCurrentElement_ToPack_b :: Start; index:",index);

if ( buttonDisabled() || isAnimLoading() ){
if (debugVerbose) console.log("[DEBUG] addCurrentElement_ToPack_b :: main button Disabled ...retry; index:",index);
if (!handleTimeout() ) return false;
setTimeout(addCurrentElement_ToPack_b, timeMod(250));
return false;
}
resetTimeout();

if ( selectInPack() ) {
debugRetries_b = 0;
setTimeout(addCurrentElement_ToPack_c, timeMod(250));
return true;
} else {
++debugRetries_b;
if (debugVerbose) console.log("[DEBUG] addCurrentElement_ToPack_b :: Start; debugRetries_b:",debugRetries_b,"; index:",index);

if (debugRetries_b <= 2) {
if (debugVerbose) console.log("[DEBUG] addCurrentElement_ToPack_b :: debugRetries_b:",debugRetries_b);
setTimeout( addCurrentElement_ToPack_b, timeMod(100 * debugRetries_b));
} else {
setTimeout( nextElementToPack, timeMod(100));
if (debugVerbose) console.log("[DEBUG] addCurrentElement_ToPack_b :: debugRetries_b:",debugRetries_b);
}
return false;
}
}

function addCurrentElement_ToPack_c(){
if (debugVerbose) console.log("[DEBUG] addCurrentElement_ToPack_c :: Start; index:",index);
var errorDelay = 50 * debugRetries;

if ( buttonDisabled() || isAnimLoading() ){
if (debugVerbose) console.log("[DEBUG] addCurrentElement_ToPack_c :: main button Disabled ...retry; index:",index);
if (!handleTimeout() ) return false;
setTimeout(addCurrentElement_ToPack_c, timeMod(250));
return false;
}
resetTimeout();

setTimeout( setCheckBoxes, timeMod(250 + errorDelay));

if (debugVerbose) console.log("[DEBUG] addCurrentElement_ToPack_c :: errorDelay:",errorDelay);

verifyError = 0;
setTimeout( selectInPack_verify,   timeMod(500 + errorDelay) );
}

var verifyError = 0;
function selectInPack_verify(){
if (debugVerbose) console.log("[DEBUG] selectInPack_verify :: Start; verifyError:",verifyError,"; index:",index);

if ( buttonDisabled() || isAnimLoading() ){
if (debugVerbose) console.log("[DEBUG] selectInPack_verify :: main button Disabled ...retry; index:",index);
if (!handleTimeout() ) return false;

setTimeout(selectInPack_verify, timeMod(250));
return false;
}
resetTimeout();


if (!selectInPack() ) {
++verifyError;
if (debugVerbose) console.log("[DEBUG] selectInPack_verify :: False; verifyError:",verifyError,"; index:",index);
}
if (debugVerbose && verifyError==0) console.log("[DEBUG] selectInPack_verify :: True; verifyError:",verifyError,"; index:",index);

var errorDelay = 50 * debugRetries;
setTimeout( afterAddToPack, timeMod(250 + errorDelay));
return true;
}

function afterAddToPack(){
if (debugVerbose) console.log("[DEBUG] afterAddToPack :: Start; index:",index);

if ( buttonDisabled() || isAnimLoading() ){
if (debugVerbose) console.log("[DEBUG] afterAddToPack :: main button Disabled ...retry; index:",index);
if (!handleTimeout() ) return false;
setTimeout(afterAddToPack, timeMod(250 + getDelay() ));
return false;
}
resetTimeout();

if (verifyError==0 && validateVariations()) {
var anim = getAnimName();
addToCurrItems( getAnimName() );
incIndex();
++numInCurrentPack;
if (debugVerbose) console.log("[DEBUG] afterAddToPack :: ++index:",index);
} else {
if (verifyError>0) console.log("[DEBUG] afterAddToPack :: selectInPack_verify failed; verifyError:",verifyError);

if (setupBeepOnRetry) beepWarning();
if (debugVerbose) console.log("[DEBUG] afterAddToPack :: Verification failed; debugRetries:",debugRetries,"; index:",index);
numClickedAddToPack=0;
setTimeout(startElement_c, timeMod(250));
return false;
}

if (debugVerbose) console.log("[DEBUG] afterAddToPack :: End");
setTimeout(nextElementToPack, timeMod(0));
}

function addToPack(){
if (debugVerbose) console.log("[DEBUG] addToPack :: Start; index:",index);
var btns = document.getElementsByClassName( setupAddToPackButtonClass );
if (btns && btns.length>0) {
if (numClickedAddToPack==0) {
btns[0].click();
if (debugVerbose) console.log("[DEBUG] addToPack :: Added To Pack; clicked");
} else {
if (debugVerbose) console.log("[DEBUG WARNING] addToPack :: Already Added To Pack; numInCurrentPack:",numInCurrentPack);
setTimeout(nextElementToPack, timeMod(100));
return false;
}
++numAssetsAdded;

++numClickedAddToPack;
++numInCurrentPackAttempted;
if (index==0) renamePack();
} else if (debugVerbose) console.log("[DEBUG] addToPack :: AddToPack Button not visible; btns:",btns);
}

var debugTimeoutCounter = 0;
function handleTimeout(){
++debugTimeoutCounter;
if (debugVerbose) console.log("[DEBUG] handleTimeout :: debugTimeoutCounter:",debugTimeoutCounter);
if (debugTimeoutCounter >= 20) {
resetTimeout();
if (debugVerbose) console.log("[DEBUG] handleTimeout :: nextElementToPack; debugTimeoutCounter:",debugTimeoutCounter);

++debugRetries;

if (!setupAddToAssets) {
setTimeout( nextElementToPack, 500);
} else {
setTimeout( nextElementToAssets, 500);
}
if (setupBeepOnRetry) beepWarning();
return false;
}
return true;
}

function resetTimeout(){
debugTimeoutCounter = 0;
if (debugVerbose) console.log("[DEBUG] resetTimeout :: debugTimeoutCounter:",debugTimeoutCounter);
}

function getTimeout(){
return debugTimeoutCounter;
}

function getDelay(){
return getTimeout() * 100;
}

function incIndex(){
if (debugVerbose) console.log("[DEBUG] incIndex :: Start; index:",index);

++index;

debugRetries = -1;

if (!setupAddToAssets) {
savePack();
if (setupBeepOnAdd) beepOnAdd();
} else {
buttonClicked = 0;
}

if (debugVerbose) console.log("[DEBUG] incIndex :: End; index:",index);
}

function reloadPage() {
if (debugVerbose) console.log("[DEBUG] reloadPage :: Start; index:",index);
scriptPaused = true;
var newUrl = "";
newUrl = pageURL + "&limit=" + pageLimit + "&page=" + pageNum.toString();

if (debugVerbose) console.log("[DEBUG] reloadPage :: ",newUrl);
document.location.href = newUrl;

setTimeout( mixamoScript, timeMod(2000) );
}

function onFinish(){
timeEnd = Date.now();
scriptPaused = true;
if (debugVerbose) console.log("[DEBUG]MixamoScript: Added (", numAssetsAdded, ")" );

if (setupBeepOnFinish) {
soundOnFinish();
setTimeout(promptOnEnd, 2000);
} else setTimeout(promptOnEnd, 0);
}

function promptOnEnd(){
var txt = "";
var t = (timeEnd-timeStart);
t = parseInt(t / 1000 / 60) + ":" + Math.floor(t / 1000 % 60);

if (!setupAddToAssets){
txt = numPacks+" Packs Saved"+
"
"+(numInPacksTotal)+" Anims In All Packs"+
"
"+numSkippedTotal+" Skipped (collections)
";

} else txt += "
Assets Added: "+numAssetsAdded+ "
In Assets Total: "+numInAssetsTotal +"
"+ printPageSummary();

txt += "

Skipped / Collections:
"+printIgnored();

if (debugVerbose) console.log("[DEBUG] promptOnEnd :: Skipped / Collections: ",printIgnored() );
if (debugVerbose) console.log("[DEBUG] promptOnEnd :: Page Summary: ",printPageSummary() );


alert("Mixamo Script: Done in "+t+"

"+txt);
if (debugVerbose) console.log("[DEBUG] promptOnEnd :: End");

}

function beepOnAdd(){
if (debugVerbose) console.log("[DEBUG] beepOnAdd :: Start; index:",index);
beep(225, 200, 0.3, "triangle");
}

function beepWarning(){
if (debugVerbose) console.log("[DEBUG] beepWarning :: Start; index:",index);
beep(250, 300, 0.35, "sine");
}

function soundOnFinish(){
setTimeout(soundOnPageEnd, (0));
setTimeout(soundOnPageEnd, (700));
setTimeout(soundOnPageEnd, (1100));
}

function soundOnPageEnd(){
beep(200, 300, 0.05, "sawtooth");
beep(550, 200, 0.2, "triangle");
beep(800, 150, 0.15, "sine");
}

function onEndOfPage() {
if (debugVerbose) console.log("[DEBUG] onEndOfPage :: Start; index:",index);
scriptPaused = true;

var t = 0;
if (setupBeepOnPage) {
t = 1000;
soundOnPageEnd();
}

printToLogCurrItems();

if (setupAddToAssets) setTimeout(onEndOfPage_Assets, t);
else setTimeout(onEndOfPage_Pack, t);
}

var pageSummary = ];
function printPageSummary(){
var r = "";
var arrayLength = pageSummary.length;
for (var i = arrayLength-1; i >= 0; i--) {
r += pageSummary* + "
";    
}
return r;
}

function onEndOfPage_Assets(){
if (debugVerbose) console.log("[DEBUG] onEndOfPage_Assets :: Start; index:",index);

numSkippedTotal   += skipped;
numInAssetsTotal += numInAssetsCurrPage;
numAssetsAdded   += numAssetsAddedCurrPage;

var summary = "
Page: "+pageNum+
 "
Assets Added: "+numAssetsAddedCurrPage+" (Total: "+numAssetsAdded+")"+
 "
Checked / In Library: "+numInAssetsCurrPage+" (Total: "+numInAssetsTotal+")"+

 "
skipped: "+skipped+" (Total: "+numSkippedTotal+")";
pageSummary.push(summary);

setTimeout(onEndOfPage_AssetsEx, 1000);
if (debugVerbose) console.log("[DEBUG] onEndOfPage_Assets :: Start; pageNum:",pageNum,"; pageMax:",pageMax);
}

function onEndOfPage_AssetsEx(){
if (setupPromptOnEndOfPage && promptNextPage_Assets()==false) {
onFinish();
return false;
}

if (pageNum >= pageMax) {
setTimeout( onFinish, timeMod(2000) );
if (debugVerbose) console.log("[DEBUG] onEndOfPage_Assets :: Start; pageNum:",pageNum,"; pageMax:",pageMax);
return;
} else {
if (!debugNoPageTurn) {
index = 0;
++pageNum;
setTimeout(reloadPage, timeMod(2000));
}
}
}

function updateStatus(){
if (debugVerbose) console.log("[DEBUG] updateStatus :: Start; index:",index);

++numPacks;
numSkippedTotal += skipped;
numInPacksTotal += numInCurrentPack;
numInPacksTotalAttempted += numInCurrentPackAttempted;

debugStatusString = printStatusAsString();

if (debugVerbose) console.log("[DEBUG] updateStatus :: debugStatusString:",debugStatusString);
numInCurrentPack = 0;
numInCurrentPackAttempted = 0;
}

function onEndOfPage_Pack(){
if (debugVerbose) console.log("[DEBUG] onEndOfPage_Pack :: Start; index:",index);
setTimeout( savePack, timeMod(500) );
setTimeout( onEndOfPage_PackEx(), 1000 );
if (debugVerbose) console.log("[DEBUG] onEndOfPage_Pack :: End");
}

function promptNextPage_Assets(){
var txt = "Finished Page "+pageNum+" of "+pageMax+". Continue with next page?"+printPageSummary()
//+"Anims From This Page:
"+printCurrItems()
+"Ignored Items:
"+printIgnored();

var r = confirm( txt );
return (r == true);
}

function promptNextPage(){
var txt = "Finished Page "+pageNum+" of "+pageMax+".

" + debugStatusString;
txt +=  "

Continue with next page?";

//txt += "

Anims From This Page:
"+printCurrItems();

if (setupAllowManualPackSave) {
txt += "


You will now have "+setupTimeManualName/1000+" seconds to rename the pack. After that the script continues. Note: to use the generated pack name, just click on the text field and wait for the script to continue.

Time before continuing (1000 = 1 second)";

var input = prompt(txt,setupTimeManualName.toString());
if (input != null) {
if (isNaN( input )) input="0";
setupTimeManualName = clamp( input, 100, 30000);
//alert(setupTimeManualName.toString()+"; "+input);
return true;
} else return false;

} else {
var r = confirm( txt );
return (r == true);
}
}

function onEndOfPage_PackEx(){
if (debugVerbose) console.log("[DEBUG] onEndOfPage_PackEx :: Start; index:",index);

updateStatus();
if ((setupPromptOnEndOfPage || setupAllowManualPackSave) && promptNextPage()==false) {
onFinish();
return false;
}

if (pageNum >= pageMax) {
setTimeout( onFinish, timeMod(5000) );
if (debugVerbose) console.log("[DEBUG] onEndOfPage_PackEx :: pageNum:",pageNum,"; pageMax:",pageMax);
return;
} else {
if (!debugNoPageTurn) {
index = 0;
++pageNum;

if (setupAllowManualPackSave) {
setTimeout(onManualPackSave, setupTimeManualName);
} else setTimeout(reloadPage, timeMod(2000));
}
}
if (debugVerbose) console.log("[DEBUG] onEndOfPage_PackEx :: End; pageNum:",pageNum,"; pageMax:",pageMax);
}

var numManualPackSave=0;
function onManualPackSave(){
var result = false;
if (setupManualSavePrompt2) {
var t2 = debugtimeManualName + (5000 * numManualPackSave);
var txt = "OK = continue with next page 
Cancel = more time to save pack ("+t2/1000+" seconds)";
result = confirm( txt );
} else result = true;

if (result == true) {
setTimeout(savePack, 100);
setTimeout(reloadPage, 200);
numManualPackSave=0;
} else {
setTimeout(onManualPackSave, timeMod( t2 ));
++numManualPackSave;
}
}

function clickViewDownload() {
if (debugVerbose) console.log("[DEBUG] clickViewDownload :: Start; index:",index);
button = document.querySelector( setupElementID_AddToAssets );
if (!button || button.disabled == true) {
if (debugVerbose) console.log("[DEBUG] clickViewDownload :: Failed; button not found or disabled");
return false;
}

if (button.textContent == setupElementID_AddToCartCaption) {
button.click();
if (debugVerbose) console.log("[DEBUG] clickViewDownload :: Failed; button.textContent:",button.textContent,"; expected:",setupElementID_AddToCartCaption);
return false;
}

if (button.textContent == setupElementID_ViewDownload) {
button.click();
if (debugVerbose) console.log("[DEBUG] clickViewDownload :: Success");
return true;
}
if (debugVerbose) console.log("[DEBUG] clickViewDownload :: Failed; Unknown issue");
return false;
}

function clickElement( elementName, elementCaption ){
if (debugVerbose) console.log("[DEBUG] clickElement :: Start; index:",index);
var elementCheck = document.getElementsByClassName( elementName );
if (!elementCheck) return false;
if (elementCheck.length <= 0) return false;
if (elementCheck[0].disabled == true) return false;
if (elementCheck[0].textContent != elementCaption) return false;

elementCheck[0].click();
if (debugVerbose) console.log("[DEBUG] clickElement :: Success; elementName:",elementName,"; elementCaption:",elementCaption);

return true;
}

function numAnimsInPack(){
if (debugVerbose) console.log("[DEBUG] numAnimsInPack :: Start; index:",index);
var items = document.getElementsByClassName( setupInPackButtonClass );
var res = -1;
if (items) res = items.length;
else res = 0;

if (debugVerbose) console.log("[DEBUG] numAnimsInPack :: Result:",res,"; index:",index);
return res;
}

function deletePack(){
if (debugVerbose) console.log("[DEBUG] deletePack :: Start; index:",index);

var items = document.getElementsByClassName( setupElementID_DeletePack );
if (items.length > 0) {
items[0].click();
if (debugVerbose) console.log("[DEBUG] deletePack :: Deleted");
} else if (debugVerbose) console.log("[DEBUG] deletePack :: Failed");
}

function savePack(){

if (!setupSavePacks) return false;
if (debugVerbose) console.log("[DEBUG] savePack :: Start; index:",index);

var items = document.getElementsByClassName( setupElementID_SavePack );
if (items.length>0) {
items[0].click();
if (debugVerbose) console.log("[DEBUG] savePack :: Saved");
} else if (debugVerbose) console.log("[DEBUG] savePack :: Failed");
if (debugVerbose) console.log("[DEBUG] savePack :: End");
return true;
}

function renamePack(){
if (!setupRenamePacks) return false;
if (debugVerbose) console.log("[DEBUG] renamePack :: Start; index:",index);
var newName = "P" + pageNum.toString();
if (setupStateMirror)  newName += "_Mirror";
if (setupStateInPlace) newName += "_inPlace";

var items = document.getElementsByClassName( setupElementID_PackName );
if (items.length>0) {
items[0].value = newName;
if (debugVerbose) console.log("[DEBUG] renamePack :: Changed");
} else if (debugVerbose) console.log("[DEBUG] renamePack :: Failed");
if (debugVerbose) console.log("[DEBUG] renamePack :: End");
}

function clickPackName(){
var items = document.getElementsByClassName( setupElementID_PackName );
if (items && items.length > 0)
items[0].kmousseup();
else console.log("FALSE");
}

function clickPackName2(){
//--- Get the first link that has "stackoverflow" in its URL.
var items = document.getElementsByClassName( setupElementID_PackName );
if (items && items.length > 0) {
var targetNode = items[0];
if (targetNode) {
//--- Simulate a natural mouse-click sequence.
triggerMouseEvent (targetNode, "mouseover");
triggerMouseEvent (targetNode, "mousedown");
triggerMouseEvent (targetNode, "mouseup");
triggerMouseEvent (targetNode, "click");
}
else console.log ("*** Target node not found!");
} else console.log(" *** error *** ");
}

function triggerMouseEvent (node, eventType) {
    var clickEvent = document.createEvent ('MouseEvents');
    clickEvent.initEvent (eventType, true, true);
    node.dispatchEvent (clickEvent);
}

function setCheckBoxes() {
if (debugVerbose) console.log("[DEBUG] setCheckBoxes :: Start; index:",index);
if (checkElement(setupElementID_Mirror, setupStateMirror)) {
if (debugVerbose) console.log("[DEBUG] setCheckBoxes :: Mirror checked; index:",index);
}
if (checkElement(setupElementID_InPlace, setupStateInPlace)) {
if (debugVerbose) console.log("[DEBUG] setCheckBoxes :: InPlace checked; index:",index);
}
}

function hasElement(x) {
return document.getElementsByName(x).length != 0;
}

function isChecked(x) {
var docElement = document.getElementsByName(x);
return (docElement.length > 0 && docElement[0].checked);
}

function checkElement(elementName, desiredState) {
var element = document.getElementsByName(elementName);
if (element.length != 0) {
if (element[0].checked != desiredState) {
if (debugVerbose) console.log("[DEBUG] checkElement :: Clicked; previous state:",element[0].checked,"; elementName:",elementName,"; desiredState:",desiredState);
element[0].click();
} else if (debugVerbose) console.log("[DEBUG] checkElement :: Element already has desired state; elementName:",elementName,"; desiredState:",desiredState);

return true;
}
if (debugVerbose) console.log("[DEBUG] checkElement :: Element not found; elementName:",elementName,"; desiredState:",desiredState);

return false;
}

var ignoredItems = ];
function addToIgnored(animName){
var t = animName.toLowerCase();
//if (ignoredItems.indexOf( t ) == -1 )
ignoredItems.push( "P"+pageNum+" | ("+index+"): " +t );
}

function printIgnored(){
var r = "";
var arrayLength = ignoredItems.length;
for (var i = 0; i < arrayLength; i++) {
r += ignoredItems* + "
";    
}
return r;
}

var currItems = ];
function addToCurrItems(animName){
if (debugVerbose) console.log("[DEBUG] addToCurrItems :: animName: "+animName+"; index: "+index);
var t = animName.toLowerCase();
//if (ignoredItems.indexOf( t ) == -1 )
currItems.push( "P"+pageNum+" ("+index+"): " +t );
}

function printCurrItems(){
var r = "";
var arrayLength = currItems.length;
for (var i = 0; i < arrayLength; i++) {
r += currItems* + "
";    
}
return r;
}

function printToLogCurrItems(){


var arrayLength = currItems.length;
console.log("[DEBUG] printToLogCurrItems; length: ",arrayLength);
for (var i = 0; i < arrayLength; i++) {
console.log(i,": ",currItems*);
}
}


function clamp(num, min, max) {
return num <= min ? min : num >= max ? max : num;
}

if (validateUrl()) mixamoScript();

Thanks for the skeleton. Though are there any ideas how to generally create/save FUSE characters with such a skeleton or how to import FUSE characters to the default skeleton with Blender?

Also notice that when you queue InPlace items, you have to manually re tick the inPlace option after preparing for euque download. Also animations added vanished from my account after weeks or months, it seems.

To what end? In order to return it to the default state?
Also, If you perform changes inside a pack, the original animation should stay unaffected (after you close the pack).

You mean, they were deleted from your assets and you had to re-add them from the store? Or did you have animations there which are no longer offered in the store?

When you select a InPlace animation and add it to your current pack, the InPlace option is not saved, when ticked. You need to tick this option after you view/queue for download.

Animations i’ve added and were marked as owned disappeared from my account.

The script takes that into account and re-selects the active animation from the list in the current pack, before applying the settings. Try it out and let me know if it works for you.

How would we go about converting a character made in Fuse to the Unreal skeleton? You used to be able to export it with the UE4 skeleton, but they removed that. Is there a Maya or Max script? Or is this done in-engine somehow? Which format should I export my Fuse character as after auto-rigging it with mixamo to get the best results? Any answers would be appreciated. Thanks!
I’m sorry if this question has already been answered in the thread. I read through and couldn’t find a definitive answer.