<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>养了一只仓鼠</title>
<style>
* {
box-sizing: border-box;
}
body {
padding: 0;
margin: 0;
font-family: sans-serif;
background-color: #728194;
color: white;
--wheel-width: 160px;
--handle-color: #3b4652;
}
p,
h1,
h2,
h3,
h4 {
display: inline-block;
margin-block-start: 0em;
margin-block-end: 0em;
margin-inline-start: 0px;
margin-inline-end: 0px;
padding-inline-start: 0px;
}
.wrapper {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
width: 100%;
height: 100%;
--hamster-speed: 0.25s;
--wheel-speed: 0.5s;
--wheel-angle: 0deg;
}
.pix,
.pix:after {
--m: 2;
position: absolute;
width: calc(var(--w) * var(--m));
height: calc(var(--h) * var(--m));
background-size: 100%;
background-repeat: no-repeat;
image-rendering: pixelated;
}
.puff {
--w: 15px;
--h: 14px;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAOCAYAAADwikbvAAAAAXNSR0IArs4c6QAAAEhJREFUOE9jZEADjzZk/UcXg/HlAqYxIsvBOfg0oRsGMwSsmRSNyK5gJEcjzIBRzbgiGIf4AAYYRYkE5h1SEgtK8kQOD1IyBgBNBC/ng5m19gAAAABJRU5ErkJggg==);
}
:before,
:after {
position: absolute;
content: '';
width: calc(var(--w) * var(--m));
height: calc(var(--h) * var(--m));
}
.ear {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAAXNSR0IArs4c6QAAACJJREFUGFdjZGBgYHi0Ies/iAYBuYBpjIzIAjAJEgSxmQkAyjQQ9ygpCP0AAAAASUVORK5CYII=);
--w: 5px;
--h: 5px;
top: -4px;
left: 6px;
}
.hamster {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px;
margin-bottom: 6px;
z-index: 99;
}
.hamster:before {
background: #693215;
width: 3px;
height: 4px;
left: 5px;
}
.hamster:after {
background: #693215;
width: 6px;
height: 2px;
bottom: 7px;
left: -3px;
}
.ear,
.hamster:before,
.hamster:after {
animation: up-down infinite var(--hamster-speed);
}
.head,
.bum {
z-index: -1;
top: 0px;
animation: squidge var(--hamster-speed) infinite;
}
.hamster div:after {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAGCAYAAADkOT91AAAAAXNSR0IArs4c6QAAACFJREFUGFdjZGBgYHi0Ies/iJYLmMbICOOABECAHAF0QwFBIRPzdQwRVAAAAABJRU5ErkJggg==);
--w: 4px;
--h: 6px;
bottom: -4px;
animation: run var(--hamster-speed) infinite;
}
.head {
left: -5px;
--angle: 10deg;
}
.bum {
right: -5px;
--angle: -10deg;
}
.head:after {
left: 8px;
--run-x: -2px;
--angle: 6deg;
}
.bum:after {
right: 6px;
--run-x: 2px;
--angle: -6deg;
}
@keyframes squidge {
0%,
100% {
transform: rotate(var(--angle)) translateY(-1px);
}
50% {
transform: rotate(0) translateY(0);
}
}
@keyframes run {
0%,
100% {
transform: translateX(var(--run-x)) rotate(var(--angle));
}
50% {
transform: translateX(0) rotate(0);
}
}
@keyframes up-down {
0%,
100% {
transform: translateY(-1px);
}
50% {
transform: translateY(0);
}
}
.wheel-frame {
position: relative;
--w: 80px;
--h: 80px;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAYAAACOEfKtAAAAAXNSR0IArs4c6QAAAn5JREFUeF7t3NtygzAMBNDy/x9NJnScIeCLVisZkmyfbdk6LHGbkC5/N/lZ13VFtrIsy4KMzxp7ySZqWChIRI0I1GmA+4ZRLGujM9Y47iUdsDSVhdbCnbVuGuCsBkbpzN5HOGD2hkdgsxMZBnhXuCNo9D5DAJ+bmv0a501imRe1Zwow+mqyKOj8iP27AaOuINp0xnimFxcgs2AGQERNb08woHehiCaza3h6gwA9C2Q3HV0f7dEMiBaObmxmPaRXEyBScGajmWtZex4CWgtlNnNVbUvvAuxcHRrQUuCqdMxad2TQTOBo4qwG7rBOz0KAhisEAyp9Z9WWSTWBAiQAhde+p2s2pwQKkAAU3vhEORq9JVCABKDwxni1jwNeCRSgAO0C5Mh92LYEKn24aDETIG63zRCgE+54kCiBTkgl0Al3SqAOEL/kZidAAfoFyJlKoABJAXK6EihAUoCcrgQKkBQgpyuBAiQFyOlKYASg3lD1KerdGJ/ba5YABUgKkNOVwEhAHSSY5uljTQEKEBMgR1cTqBTaVPV0ls2pOaoLqBT2dfWEanD6nuX0kLkRVU/pG6FawyBAvRa+M/YePtA3lQzJdAEqhf+yo0df9HXXTgJHeM1TeF/TUsRwF3zkEEvvwwRaYvyROoNNW/BMCSzrWAt+AybSqymBv4SI4EEJ/AVEFM8F+K2viR48N+C3IXrxKMCCuBW5yb8kRg+wJxy7f+gQQf/QRhuaOZ5J3X6fIYCflMaI1KUA7k9p9rbISGI0XNljWAKPTWdtGMXN3kca4NWJzIZLT2ArkZm3d0HLXOPYV3oCa7fcvtHXlQR/FYqogb4c1MZfAmhF7TV4l989H/4WeD/sciFJAAAAAElFTkSuQmCC);
margin-bottom: 16px;
pointer-events: none;
}
.wheel {
width: 160px;
height: 160px;
display: flex;
justify-content: center;
align-items: end;
transform: rotate(var(--wheel-angle));
}
.wheel.spinning {
animation: spin var(--wheel-speed) infinite linear;
}
.wheel.spinning .hamster {
animation: none;
}
.wheel-support {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAYAAACOEfKtAAAAAXNSR0IArs4c6QAAAURJREFUeF7t28EJwkAARUHTpR3YgUXYgR3YpbKCVw3MKos8729JJv+QQ9wO/Uhgo/oL8fF0vr879na9LHXNS13MgAsQVxlggCiAeQsMEAUwb4EBogDmLTBAFMC8BQaIApi3wABRAPMWGCAKYN4CA0QBzFtggCiAeQsMEAUwb4EBogDmLTBAFMC8BQaIApi3wABRAPMWGCAKYN4CA0QByD+t73X0Sl+pPr9Q3XvhYPOX6XiQAcKjDRDwRhpggCiAeQsMEAUwb4GzAPGcafne99HlXqSnCUw46BPiSnjjdvuvHD70AANEAcxbYIAogHkLDBAFMG+BAaIA5i0wQBTAvAUGiAKYt8AAUQDzFhggCmDeAgNEAcxbYIAogHkLDBAFMG+BAaIA5i0wQBTAvAUGiAKYt8AAUQDzFhggCmC+3ALxfn6ePwDuUzhgOFkZ9gAAAABJRU5ErkJggg==);
animation: spin var(--wheel-speed) infinite linear;
--w: 80px;
--h: 80px;
}
@keyframes spin {
to {
transform: rotate(-360deg);
}
}
input[type='range'] {
width: var(--wheel-width);
padding: 0;
background-color: transparent;
-webkit-appearance: none;
appearance: none;
}
input[type='range']:focus {
outline: none;
}
input[type='range']::-webkit-slider-runnable-track {
background: #fff;
width: var(--wheel-width);
height: 4px;
cursor: pointer;
}
input[type='range']::-webkit-slider-thumb {
margin: -8.2px 0 0 0;
width: 20px;
height: 20px;
background: var(--handle-color);
cursor: pointer;
-webkit-appearance: none;
}
input[type='range']:focus::-webkit-slider-runnable-track {
background: #fff;
}
input[type='range']::-moz-range-track {
background: #fff;
width: var(--wheel-width);
height: 4px;
cursor: pointer;
}
input[type='range']::-moz-range-thumb {
width: 20px;
height: 20px;
background: var(--handle-color);
cursor: pointer;
}
input[type='range']::-ms-track {
background: transparent;
border-color: transparent;
border-width: 9px 0;
color: transparent;
width: var(--wheel-width);
height: 4px;
cursor: pointer;
}
input[type='range']::-ms-fill-lower {
background: #fff;
}
input[type='range']::-ms-fill-upper {
background: #fff;
}
input[type='range']::-ms-thumb {
width: 20px;
height: 20px;
background: var(--handle-color);
cursor: pointer;
margin-top: 0px;
}
input[type='range']:focus::-ms-fill-lower {
background: #fff;
}
input[type='range']:focus::-ms-fill-upper {
background: #fff;
}
.sign {
position: fixed;
font-family: Arial, Helvetica, sans-serif;
color: rgb(255, 255, 255);
bottom: 10px;
right: 10px;
font-size: 10px;
text-transform: none;
}
a {
color: rgb(255, 255, 255);
text-decoration: none;
text-transform: none;
}
a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="wheel-frame pix">
<div class="wheel">
<div class="wheel-support pix"></div>
<div class="hamster puff pix">
<div class="ear pix"></div>
<div class="head puff pix"></div>
<div class="bum puff pix"></div>
</div>
</div>
</div>
<input type="range" name="speed" min="0" max="11" value="3" />
</div>
<script>
function init() {
const wrapper = document.querySelector('.wrapper');
const wheel = document.querySelector('.wheel');
const defaultHamsterEnergy = 1000;
const hamster = {
energy: defaultHamsterEnergy,
speedFactor: 4,
isRunning: true,
};
const setSpeed = () => {
wrapper.style.setProperty(
'--hamster-speed',
`${1 / hamster.speedFactor}s`
);
wrapper.style.setProperty(
'--wheel-speed',
`${2 / hamster.speedFactor}s`
);
wrapper.style.setProperty(
'--wheel-angle',
`${0.4 * hamster.speedFactor}deg`
);
};
document.querySelector('input').addEventListener('input', (e) => {
hamster.speedFactor = e.target.value;
setSpeed();
});
setInterval(() => {
if (hamster.isRunning) {
hamster.energy -= hamster.speedFactor * hamster.speedFactor;
}
if (hamster.isRunning && hamster.energy < 0) {
hamster.isRunning = false;
wheel.classList.add('spinning');
setTimeout(() => {
hamster.energy = defaultHamsterEnergy;
hamster.isRunning = true;
wheel.classList.remove('spinning');
}, 6 * 1000);
}
}, 500);
setSpeed();
}
window.addEventListener('DOMContentLoaded', init);
</script>
</body>
</html>