Tip of the day
Want to find something particular about the game and don't mind spoilers? Check the Wiki!
MediaWiki:Gadget-AnimatedCursorFollower.js
From Walkscape Walkthrough
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/**
* 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'
});
// Let the existing ws-sprite CSS/JS handle sprite rendering.
pet.removeAttribute('style');
pet.className = sourceNode.className;
pet.style.setProperty('--scale', String(CONFIG.scale));
pet.style.display = 'inline-block';
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-wrapper span.ws-sprite)'
);
if (!sprite) {
setTimeout(init, 500);
return;
}
mountPet(sprite);
}
$(init);
}());
