mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Animate VN mode expression changes
This commit is contained in:
@@ -152,7 +152,7 @@ async function visualNovelSetCharacterSprites(container, name, expression) {
|
|||||||
|
|
||||||
const path = currentSpritePath || defaultSpritePath || '';
|
const path = currentSpritePath || defaultSpritePath || '';
|
||||||
const img = expressionImage.find('img');
|
const img = expressionImage.find('img');
|
||||||
setImage(img, path);
|
await setImage(img, path);
|
||||||
}
|
}
|
||||||
expressionImage.toggleClass('hidden', noSprites);
|
expressionImage.toggleClass('hidden', noSprites);
|
||||||
} else {
|
} else {
|
||||||
@@ -163,7 +163,7 @@ async function visualNovelSetCharacterSprites(container, name, expression) {
|
|||||||
$('#visual-novel-wrapper').append(template);
|
$('#visual-novel-wrapper').append(template);
|
||||||
dragElement($(template[0]));
|
dragElement($(template[0]));
|
||||||
template.toggleClass('hidden', noSprites);
|
template.toggleClass('hidden', noSprites);
|
||||||
setImage(template.find('img'), defaultSpritePath || '');
|
await setImage(template.find('img'), defaultSpritePath || '');
|
||||||
const fadeInPromise = new Promise(resolve => {
|
const fadeInPromise = new Promise(resolve => {
|
||||||
template.fadeIn(250, () => resolve());
|
template.fadeIn(250, () => resolve());
|
||||||
});
|
});
|
||||||
@@ -284,7 +284,9 @@ async function setLastMessageSprite(img, avatar, labels) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setImage(img, path) {
|
async function setImage(img, path) {
|
||||||
|
// Cohee: If something goes wrong, uncomment this to return to the old behavior
|
||||||
|
/*
|
||||||
img.attr('src', path);
|
img.attr('src', path);
|
||||||
img.removeClass('default');
|
img.removeClass('default');
|
||||||
img.off('error');
|
img.off('error');
|
||||||
@@ -293,6 +295,66 @@ function setImage(img, path) {
|
|||||||
$(this).off('error');
|
$(this).off('error');
|
||||||
$(this).attr('src', '');
|
$(this).attr('src', '');
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const prevExpressionSrc = img.attr('src');
|
||||||
|
const expressionClone = img.clone();
|
||||||
|
const originalId = img.attr('id');
|
||||||
|
|
||||||
|
//only swap expressions when necessary
|
||||||
|
if (prevExpressionSrc !== path && !img.hasClass('expression-animating')) {
|
||||||
|
//clone expression
|
||||||
|
expressionClone.addClass('expression-clone')
|
||||||
|
//make invisible and remove id to prevent double ids
|
||||||
|
//must be made invisible to start because they share the same Z-index
|
||||||
|
expressionClone.attr('id', '').css({ opacity: 0 });
|
||||||
|
//add new sprite path to clone src
|
||||||
|
expressionClone.attr('src', path);
|
||||||
|
//add invisible clone to html
|
||||||
|
expressionClone.appendTo(img.parent());
|
||||||
|
|
||||||
|
const duration = 200;
|
||||||
|
|
||||||
|
//add animation flags to both images
|
||||||
|
//to prevent multiple expression changes happening simultaneously
|
||||||
|
img.addClass('expression-animating')
|
||||||
|
//position absolute prevent the original from jumping around during transition
|
||||||
|
img.css('position', 'absolute')
|
||||||
|
expressionClone.addClass('expression-animating')
|
||||||
|
//fade the clone in
|
||||||
|
expressionClone.css({
|
||||||
|
opacity: 0
|
||||||
|
}).animate({
|
||||||
|
opacity: 1
|
||||||
|
}, duration)
|
||||||
|
//when finshed fading in clone, fade out the original
|
||||||
|
.promise().done(function () {
|
||||||
|
img.animate({
|
||||||
|
opacity: 0
|
||||||
|
}, duration);
|
||||||
|
//remove old expression
|
||||||
|
img.remove();
|
||||||
|
//replace ID so it becomes the new 'original' expression for next change
|
||||||
|
expressionClone.attr('id', originalId);
|
||||||
|
expressionClone.removeClass('expression-animating');
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
expressionClone.removeClass('expression-clone');
|
||||||
|
|
||||||
|
expressionClone.removeClass('default');
|
||||||
|
expressionClone.off('error');
|
||||||
|
expressionClone.on('error', function () {
|
||||||
|
console.debug('Expression image error', sprite.path);
|
||||||
|
$(this).attr('src', '');
|
||||||
|
$(this).off('error');
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function onExpressionsShowDefaultInput() {
|
function onExpressionsShowDefaultInput() {
|
||||||
@@ -640,7 +702,7 @@ async function setExpression(character, expression, force) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (groupMember.name == character) {
|
if (groupMember.name == character) {
|
||||||
setImage($(`.expression-holder[data-avatar="${member}"] img`), sprite.path);
|
await setImage($(`.expression-holder[data-avatar="${member}"] img`), sprite.path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user