add logo and cursor duck #1
183
www/cursor-thing.js
Normal file
183
www/cursor-thing.js
Normal file
@ -0,0 +1,183 @@
|
||||
|
||||
const thing = document.getElementById('cursor-thing');
|
||||
let updateTimerId;
|
||||
|
||||
let lastUpdate = 0;
|
||||
|
||||
// targeting
|
||||
let mouseX = 0;
|
||||
let mouseY = 0;
|
||||
let scrollX = document.scrollingElement.scrollLeft;
|
||||
let scrollY = document.scrollingElement.scrollTop;
|
||||
const getTargetX = () => mouseX + scrollX;
|
||||
const getTargetY = () => mouseY + scrollY;
|
||||
|
||||
// physics
|
||||
let xPos = 0;
|
||||
let yPos = 0;
|
||||
let angle = 0;
|
||||
let velocity = 0;
|
||||
const maxVel = 600;
|
||||
let accel = 0;
|
||||
const maxAccel = 1500;
|
||||
const accelCurve = (x) => maxAccel*(x/200)**3; // maxAccel when >150px distance
|
||||
|
||||
// more physics
|
||||
const slideFric = .9; // coefficient of friction
|
||||
const turnSpeedCoeff = .08; // coefficient of turning
|
||||
|
||||
// other stuff
|
||||
let brake = false;
|
||||
const brakeDist = 70;
|
||||
|
||||
// animation
|
||||
let alt = false;
|
||||
let lastAlt = 0;
|
||||
|
||||
|
||||
function update() {
|
||||
// timing
|
||||
thisUpdate = Date.now();
|
||||
deltaT = (thisUpdate - lastUpdate)/1000.0;
|
||||
lastUpdate = thisUpdate;
|
||||
|
||||
// update trajectory
|
||||
targetX = getTargetX();
|
||||
targetY = getTargetY();
|
||||
|
||||
xDelta = targetX - xPos;
|
||||
yDelta = targetY - yPos;
|
||||
|
||||
// find target angle
|
||||
let targetAngle = Math.atan(yDelta/xDelta);
|
||||
if (isNaN(targetAngle)) targetAngle = 0;
|
||||
if (xDelta < 0) targetAngle = Math.PI*.5 - (targetAngle*-1);
|
||||
else targetAngle = -((targetAngle*-1) - Math.PI*1.5);
|
||||
|
||||
// find shortest rotation delta
|
||||
let aAngle = angle;
|
||||
let aTargetAngle = targetAngle;
|
||||
if (aTargetAngle > aAngle && aTargetAngle - aAngle > Math.PI) {
|
||||
aAngle += Math.PI;
|
||||
aTargetAngle -= Math.PI;
|
||||
} else if (aAngle > aTargetAngle && aAngle - aTargetAngle > Math.PI) {
|
||||
aAngle -= Math.PI;
|
||||
aTargetAngle += Math.PI;
|
||||
}
|
||||
|
||||
rDelta = aTargetAngle - aAngle;
|
||||
|
||||
// console.log(`myAngle: ${angle * (180 / Math.PI)} target angle: ${targetAngle * (180 / Math.PI)}`)
|
||||
// console.log(`deelta: ${(rDelta) * (180 / Math.PI)} `);
|
||||
|
||||
// apply delta
|
||||
angle += rDelta * turnSpeedCoeff;
|
||||
|
||||
// counter overflow
|
||||
if (angle > 2*Math.PI) angle -= 2*Math.PI;
|
||||
else if (angle < 0) angle += 2*Math.PI;
|
||||
|
||||
// stop when close
|
||||
let dist = Math.sqrt((xPos-targetX)**2 + (yPos-targetY)**2);
|
||||
brake = dist < brakeDist;
|
||||
if (!brake) {
|
||||
accel = accelCurve(dist);
|
||||
if (accel > maxAccel) accel = maxAccel;
|
||||
else if (accel < -maxAccel) accel = -maxAccel;
|
||||
} else accel = 0;
|
||||
|
||||
// physics
|
||||
velocity += accel * deltaT;
|
||||
|
||||
if (brake) {
|
||||
// basic friction
|
||||
velocity *= slideFric;
|
||||
}
|
||||
|
||||
// vel limit
|
||||
if (velocity > maxVel) velocity = maxVel;
|
||||
else if (velocity < -maxVel) velocity = -maxVel
|
||||
|
||||
// translate vector to 2D
|
||||
let hAngle = angle % Math.PI;
|
||||
let right = angle > Math.PI;
|
||||
let xVel = Math.sin(hAngle) * velocity;
|
||||
let yVel = Math.cos(hAngle) * velocity;
|
||||
if (right) {
|
||||
yVel *= -1;
|
||||
} else {
|
||||
xVel *= -1;
|
||||
}
|
||||
|
||||
// apply velocity
|
||||
xPos += xVel * deltaT;
|
||||
yPos += yVel * deltaT;
|
||||
|
||||
// console.log(`accel: ${accel}`);
|
||||
// console.log(`velocity: ${velocity} (${xVel}, ${yVel})`)
|
||||
|
||||
let visualAngle = angle + (rDelta/2);
|
||||
visualAngle = targetAngle;
|
||||
|
||||
thing.style.left = xPos + 'px';
|
||||
thing.style.top = yPos + 'px';
|
||||
// thing.style.rotate = visualAngle + 'rad';
|
||||
// if (brake) {
|
||||
// thing.style['background-color'] = '#00ff00';
|
||||
// } else {
|
||||
// thing.style['background-color'] = '#ff0000';
|
||||
// }
|
||||
|
||||
let fuck = visualAngle + Math.PI/4;
|
||||
if (fuck < Math.PI/2 || fuck > Math.PI * 2) {
|
||||
// front-facing
|
||||
thing.style['background-position-x'] = '100px';
|
||||
} else if (fuck < Math.PI) {
|
||||
// left-facing
|
||||
thing.style['background-position-x'] = '0px';
|
||||
} else if (fuck < Math.PI*3/2) {
|
||||
// right-facing
|
||||
thing.style['background-position-x'] = '150px';
|
||||
} else {
|
||||
// back-facing
|
||||
thing.style['background-position-x'] = '50px';
|
||||
}
|
||||
|
||||
if (thisUpdate - lastAlt > 70) {
|
||||
lastAlt = thisUpdate;
|
||||
alt = !alt;
|
||||
}
|
||||
|
||||
if (velocity > 50) {
|
||||
thing.style['background-position-y'] = alt ? '50px' : '100px';
|
||||
} else {
|
||||
thing.style['background-position-y'] = '0px';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
document.addEventListener('mousemove', e => {
|
||||
mouseX = e.clientX;
|
||||
mouseY = e.clientY;
|
||||
});
|
||||
|
||||
document.addEventListener('scroll', e => {
|
||||
el = e.target.scrollingElement;
|
||||
scrollX = el.scrollLeft;
|
||||
scrollY = el.scrollTop;
|
||||
});
|
||||
|
||||
let duck_start = false;
|
||||
function click_duck() {
|
||||
if (duck_start) return;
|
||||
duck_start = true;
|
||||
|
||||
xPos = thing.offsetLeft;
|
||||
yPos = thing.offsetTop;
|
||||
thing.style.position = 'absolute';
|
||||
thing.style.cursor = 'auto';
|
||||
lastUpdate = Date.now();
|
||||
|
||||
updateTimerId = setInterval(update, 10);
|
||||
}
|
||||
|
BIN
www/img/duck-sprite.webp
Normal file
BIN
www/img/duck-sprite.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
@ -316,7 +316,7 @@
|
||||
🄯 Copyleft 2024 Benjamin Wiegand
|
||||
</div>
|
||||
<div class="footer-logo">
|
||||
> insert cool logo here <
|
||||
<div id="cursor-thing" onclick="click_duck()"></div>
|
||||
</div>
|
||||
<div class="footer-contact">
|
||||
<noscript>
|
||||
@ -350,5 +350,7 @@
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="/cursor-thing.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -288,6 +288,20 @@ body:has(.project-image > input:checked) {
|
||||
animation: fly-up .5s ease-out 0s 1 normal none;
|
||||
}
|
||||
|
||||
.footer-logo {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
#cursor-thing {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
background-image: url('/img/duck-sprite.webp');
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@keyframes fly-up {
|
||||
0% {
|
||||
transform: translateY(70%);
|
||||
|
Loading…
Reference in New Issue
Block a user