Tip of the day
Want to find something particular about the game and don't mind spoilers? Check the Wiki!
MediaWiki:Gadget-AnimatedCursorFollower.js: Difference between revisions
From Walkscape Walkthrough
mNo edit summary |
mNo edit summary |
||
| Line 33: | Line 33: | ||
state.mounted = true; | state.mounted = true; | ||
const wrapper = document.createElement('span'); | const wrapper = document.createElement('span'); | ||
const frameSize = getFrameSize(sourceNode); | const frameSize = getFrameSize(sourceNode); | ||
const centerOffset = (frameSize * CONFIG.scale) / 2; | const centerOffset = (frameSize * CONFIG.scale) / 2; | ||
let pet = null; | |||
wrapper.className = 'animated-cursor-follower-wrapper'; | wrapper.className = 'animated-cursor-follower-wrapper'; | ||
| Line 55: | Line 55: | ||
}); | }); | ||
function setPetSource(newSourceNode) { | |||
const newPet = newSourceNode.cloneNode(true); | |||
newPet.classList.add('animated-cursor-follower-pet'); | |||
newPet.style.setProperty('--scale', String(CONFIG.scale)); | |||
Object.assign(newPet.style, { | |||
position: 'static', | |||
margin: '0', | |||
pointerEvents: 'none' | |||
}); | |||
wrapper.replaceChildren(newPet); | |||
pet = newPet; | |||
} | |||
setPetSource(sourceNode); | |||
document.body.appendChild(wrapper); | document.body.appendChild(wrapper); | ||
document.addEventListener('mousemove', function (e) { | document.addEventListener('mousemove', function (e) { | ||
if (!state.hasMouse) { | if (!state.hasMouse) { | ||
state.hasMouse = true; | state.hasMouse = true; | ||
state.targetX = e.clientX; | state.targetX = e.clientX; | ||
state.targetY = e.clientY; | state.targetY = e.clientY; | ||
state.currentX = e.clientX; | state.currentX = e.clientX; | ||
state.currentY = e.clientY; | state.currentY = e.clientY; | ||
wrapper.style.display = ''; | wrapper.style.display = ''; | ||
} | } | ||
state.targetX = e.clientX; | state.targetX = e.clientX; | ||
state.targetY = e.clientY; | state.targetY = e.clientY; | ||
}, { passive: true }); | }, { passive: true }); | ||
document.documentElement.addEventListener('mouseout', function (e) { | document.documentElement.addEventListener('mouseout', function (e) { | ||
if (!e.relatedTarget && !e.toElement) { | if (!e.relatedTarget && !e.toElement) { | ||
| Line 94: | Line 97: | ||
} | } | ||
}); | }); | ||
document.addEventListener('click', function (e) { | |||
const clickedSprite = e.target.closest('span.ws-sprite'); | |||
if (!clickedSprite) return; | |||
if (clickedSprite.classList.contains('animated-cursor-follower-pet')) { | |||
return; | |||
} | |||
if (!clickedSprite.dataset.spriteApplied) { | |||
return; | |||
} | |||
setPetSource(clickedSprite); | |||
}, { passive: true }); | |||
function render() { | function render() { | ||
| Line 100: | Line 119: | ||
return; | return; | ||
} | } | ||
state.currentX += (state.targetX - state.currentX) * CONFIG.speed; | state.currentX += (state.targetX - state.currentX) * CONFIG.speed; | ||
state.currentY += (state.targetY - state.currentY) * CONFIG.speed; | state.currentY += (state.targetY - state.currentY) * CONFIG.speed; | ||
if (state.targetX > state.currentX + 1) { | if (state.targetX > state.currentX + 1) { | ||
state.facingRight = true; | state.facingRight = true; | ||
| Line 109: | Line 128: | ||
state.facingRight = false; | state.facingRight = false; | ||
} | } | ||
const scaleX = state.facingRight ? 1 : -1; | const scaleX = state.facingRight ? 1 : -1; | ||
const xOffset = state.facingRight | const xOffset = state.facingRight | ||
? -CONFIG.offsetX | ? -CONFIG.offsetX | ||
: CONFIG.offsetX; | : CONFIG.offsetX; | ||
wrapper.style.transform = | wrapper.style.transform = | ||
`translate3d(` + | `translate3d(` + | ||
| Line 121: | Line 140: | ||
`${state.currentY + CONFIG.offsetY - centerOffset}px, 0)` + | `${state.currentY + CONFIG.offsetY - centerOffset}px, 0)` + | ||
` scaleX(${scaleX})`; | ` scaleX(${scaleX})`; | ||
state.reqId = requestAnimationFrame(render); | state.reqId = requestAnimationFrame(render); | ||
} | } | ||
Revision as of 01:28, 23 May 2026
/**
* Animated Cursor Follower
*/
(function () {
'use strict';
const CONFIG = {
scale: 1,
speed: 0.5,
offsetX: 30,
offsetY: 30
};
const state = {
targetX: 0,
targetY: 0,
currentX: 0,
currentY: 0,
facingRight: true,
reqId: null,
mounted: false,
hasMouse: false
};
function getFrameSize(sprite) {
const styles = window.getComputedStyle(sprite);
return parseInt(styles.getPropertyValue('--frame'), 10) || 48;
}
function mountFollower(sourceNode) {
if (state.mounted) return;
state.mounted = true;
const wrapper = document.createElement('span');
const frameSize = getFrameSize(sourceNode);
const centerOffset = (frameSize * CONFIG.scale) / 2;
let pet = null;
wrapper.className = 'animated-cursor-follower-wrapper';
Object.assign(wrapper.style, {
position: 'fixed',
top: '0',
left: '0',
pointerEvents: 'none',
zIndex: '99999',
margin: '0',
padding: '0',
width: `${frameSize * CONFIG.scale}px`,
height: `${frameSize * CONFIG.scale}px`,
willChange: 'transform',
display: 'none'
});
function setPetSource(newSourceNode) {
const newPet = newSourceNode.cloneNode(true);
newPet.classList.add('animated-cursor-follower-pet');
newPet.style.setProperty('--scale', String(CONFIG.scale));
Object.assign(newPet.style, {
position: 'static',
margin: '0',
pointerEvents: 'none'
});
wrapper.replaceChildren(newPet);
pet = newPet;
}
setPetSource(sourceNode);
document.body.appendChild(wrapper);
document.addEventListener('mousemove', function (e) {
if (!state.hasMouse) {
state.hasMouse = true;
state.targetX = e.clientX;
state.targetY = e.clientY;
state.currentX = e.clientX;
state.currentY = e.clientY;
wrapper.style.display = '';
}
state.targetX = e.clientX;
state.targetY = e.clientY;
}, { passive: true });
document.documentElement.addEventListener('mouseout', function (e) {
if (!e.relatedTarget && !e.toElement) {
state.hasMouse = false;
wrapper.style.display = 'none';
}
});
document.addEventListener('click', function (e) {
const clickedSprite = e.target.closest('span.ws-sprite');
if (!clickedSprite) return;
if (clickedSprite.classList.contains('animated-cursor-follower-pet')) {
return;
}
if (!clickedSprite.dataset.spriteApplied) {
return;
}
setPetSource(clickedSprite);
}, { passive: true });
function render() {
if (!state.hasMouse) {
state.reqId = requestAnimationFrame(render);
return;
}
state.currentX += (state.targetX - state.currentX) * CONFIG.speed;
state.currentY += (state.targetY - state.currentY) * CONFIG.speed;
if (state.targetX > state.currentX + 1) {
state.facingRight = true;
} else if (state.targetX < state.currentX - 1) {
state.facingRight = false;
}
const scaleX = state.facingRight ? 1 : -1;
const xOffset = state.facingRight
? -CONFIG.offsetX
: CONFIG.offsetX;
wrapper.style.transform =
`translate3d(` +
`${state.currentX + xOffset - centerOffset}px, ` +
`${state.currentY + CONFIG.offsetY - centerOffset}px, 0)` +
` scaleX(${scaleX})`;
state.reqId = requestAnimationFrame(render);
}
render();
}
function init() {
const sprite = document.querySelector('span.ws-sprite');
if (!sprite || !sprite.dataset.spriteApplied) {
setTimeout(init, 250);
return;
}
mountFollower(sprite);
}
if (document.readyState === 'complete') {
init();
} else {
window.addEventListener('load', init);
}
}());
