Tip of the day
Equipping a gear set while at a bank will automatically withdraw all the items from the bank.
MediaWiki:Gadget-AnimatedCursorFollower.js: Difference between revisions
From Walkscape Walkthrough
mNo edit summary |
mNo edit summary |
||
| Line 1: | Line 1: | ||
/** | /** | ||
* Animated Cursor Follower | * Animated Cursor Follower | ||
* Clones | * Clones a WalkScape sprite and makes it follow the mouse. | ||
*/ | */ | ||
(function () { | (function () { | ||
'use strict'; | 'use strict'; | ||
const CONFIG = { | const CONFIG = { | ||
scale: 1.5, | scale: 1.5, | ||
| Line 20: | Line 20: | ||
currentY: window.innerHeight / 2, | currentY: window.innerHeight / 2, | ||
facingRight: true, | facingRight: true, | ||
reqId: null | reqId: null | ||
}; | }; | ||
let | let mounted = false; | ||
let centerOffset = 36; | let centerOffset = 36; | ||
function mountPet(sourceNode) { | function mountPet(sourceNode) { | ||
if ( | if (mounted) return; | ||
mounted = true; | |||
pet = sourceNode.cloneNode(true); | const wrapper = document.createElement('span'); | ||
const pet = sourceNode.cloneNode(true); | |||
const styles = window.getComputedStyle(sourceNode); | const styles = window.getComputedStyle(sourceNode); | ||
const frameSize = parseInt(styles.getPropertyValue('--frame'), 10) || 48; | |||
const frameSize = | |||
parseInt(styles.getPropertyValue('--frame'), 10) || 48; | |||
centerOffset = (frameSize * CONFIG.scale) / 2; | centerOffset = (frameSize * CONFIG.scale) / 2; | ||
wrapper.className = 'animated-cursor-follower-wrapper'; | |||
Object.assign( | Object.assign(wrapper.style, { | ||
position: 'fixed', | position: 'fixed', | ||
top: '0', | top: '0', | ||
| Line 85: | Line 53: | ||
}); | }); | ||
document.body.appendChild( | // Preserve sprite appearance | ||
Object.assign(pet.style, { | |||
display: 'inline-block', | |||
backgroundImage: styles.backgroundImage, | |||
backgroundSize: styles.backgroundSize, | |||
backgroundPosition: styles.backgroundPosition, | |||
backgroundRepeat: styles.backgroundRepeat, | |||
width: styles.width, | |||
height: styles.height | |||
}); | |||
pet.style.setProperty('--scale', String(CONFIG.scale)); | |||
wrapper.appendChild(pet); | |||
document.body.appendChild(wrapper); | |||
document.addEventListener('mousemove', function (e) { | document.addEventListener('mousemove', function (e) { | ||
| Line 92: | Line 74: | ||
}, { passive: true }); | }, { passive: true }); | ||
document.addEventListener('mouseleave', | document.addEventListener('mouseleave', function () { | ||
document.addEventListener('mouseenter', | if (state.reqId) { | ||
cancelAnimationFrame(state.reqId); | |||
state.reqId = null; | |||
} | |||
}); | |||
document.addEventListener('mouseenter', function () { | |||
if (!state.reqId) { | |||
render(); | |||
} | |||
}); | |||
function render() { | |||
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; | |||
wrapper.style.transform = | |||
`translate3d(` + | |||
`${state.currentX - centerOffset}px, ` + | |||
`${state.currentY - centerOffset}px, 0)` + | |||
` scaleX(${scaleX})`; | |||
state.reqId = requestAnimationFrame(render); | |||
} | |||
render(); | |||
} | } | ||
function init() { | function init() { | ||
const sprite = document.querySelector('span.ws-sprite'); | const sprite = document.querySelector( | ||
'span.ws-sprite:not(.animated-cursor-follower)' | |||
); | |||
if (!sprite) return; | if (!sprite) { | ||
setTimeout(init, 500); | |||
return; | |||
} | |||
mountPet(sprite); | mountPet(sprite); | ||
| Line 107: | Line 128: | ||
$(init); | $(init); | ||
}()); | }()); | ||
Revision as of 01:06, 23 May 2026
/**
* Animated Cursor Follower
* Clones a WalkScape sprite and makes it follow the mouse.
*/
(function () {
'use strict';
const CONFIG = {
scale: 1.5,
speed: 0.5,
offsetX: 30,
offsetY: 30
};
const state = {
targetX: window.innerWidth / 2,
targetY: window.innerHeight / 2,
currentX: window.innerWidth / 2,
currentY: window.innerHeight / 2,
facingRight: true,
reqId: null
};
let mounted = false;
let centerOffset = 36;
function mountPet(sourceNode) {
if (mounted) return;
mounted = true;
const wrapper = document.createElement('span');
const pet = sourceNode.cloneNode(true);
const styles = window.getComputedStyle(sourceNode);
const frameSize =
parseInt(styles.getPropertyValue('--frame'), 10) || 48;
centerOffset = (frameSize * CONFIG.scale) / 2;
wrapper.className = 'animated-cursor-follower-wrapper';
Object.assign(wrapper.style, {
position: 'fixed',
top: '0',
left: '0',
pointerEvents: 'none',
zIndex: '99999',
margin: '0',
willChange: 'transform',
transition: 'none'
});
// Preserve sprite appearance
Object.assign(pet.style, {
display: 'inline-block',
backgroundImage: styles.backgroundImage,
backgroundSize: styles.backgroundSize,
backgroundPosition: styles.backgroundPosition,
backgroundRepeat: styles.backgroundRepeat,
width: styles.width,
height: styles.height
});
pet.style.setProperty('--scale', String(CONFIG.scale));
wrapper.appendChild(pet);
document.body.appendChild(wrapper);
document.addEventListener('mousemove', function (e) {
state.targetX = e.clientX + CONFIG.offsetX;
state.targetY = e.clientY + CONFIG.offsetY;
}, { passive: true });
document.addEventListener('mouseleave', function () {
if (state.reqId) {
cancelAnimationFrame(state.reqId);
state.reqId = null;
}
});
document.addEventListener('mouseenter', function () {
if (!state.reqId) {
render();
}
});
function render() {
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;
wrapper.style.transform =
`translate3d(` +
`${state.currentX - centerOffset}px, ` +
`${state.currentY - centerOffset}px, 0)` +
` scaleX(${scaleX})`;
state.reqId = requestAnimationFrame(render);
}
render();
}
function init() {
const sprite = document.querySelector(
'span.ws-sprite:not(.animated-cursor-follower)'
);
if (!sprite) {
setTimeout(init, 500);
return;
}
mountPet(sprite);
}
$(init);
}());
