<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>彩色像素骷髅</title>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css"
/>
<style>
#count {
display: none;
}
canvas {
display: none;
}
:root {
--tile-size: 0.7vmin;
--distance: 1vmin;
}
@property --x {
syntax: '<length>';
initial-value: 0;
inherits: true;
}
@property --y {
syntax: '<length>';
initial-value: 0;
inherits: true;
}
@property --scale {
syntax: '<number>';
initial-value: 1;
inherits: true;
}
#tiles {
filter: drop-shadow(0 0 1rem black);
display: grid;
place-items: center;
cursor: pointer;
translate: 0 -12vh;
}
#tiles > div {
border-radius: 50%;
width: var(--tile-size);
aspect-ratio: 1;
background: hsla(var(--hue), 100%, calc(50% + var(--light) * 50%), 1);
position: absolute;
transform: translate3d(var(--x), var(--y), 0) scale(var(--scale));
--delay: calc(var(--p-r) * 1s);
--hue: calc(var(--p-r) * (361 - 80) + 80);
--light: calc((var(--p-r) * (0.5 - 0.05) + -0.05));
--duration: calc(var(--p-r2) * 10s);
}
#tiles.show > div {
-webkit-animation: fade-in 0.3s linear forwards,
show var(--duration) var(--delay) cubic-bezier(0.86, 0.86, 0.41, 1.16)
infinite,
blink 1s var(--delay) ease-in-out infinite;
animation: fade-in 0.3s linear forwards,
show var(--duration) var(--delay) cubic-bezier(0.86, 0.86, 0.41, 1.16)
infinite,
blink 1s var(--delay) ease-in-out infinite;
}
@-webkit-keyframes blink {
from,
50%,
to {
opacity: 1;
}
30%,
70% {
opacity: 0.3;
}
}
@keyframes blink {
from,
50%,
to {
opacity: 1;
}
30%,
70% {
opacity: 0.3;
}
}
@-webkit-keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@-webkit-keyframes show {
from {
--x: calc(1dvw * var(--p-r));
--y: calc(-100dvh * var(--p-r));
filter: blur(0.5rem);
--scale: calc(clamp(1.5, 10 * var(--p-r2), 5));
}
5% {
filter: blur(0rem);
}
10% {
--x: calc(var(--p-x) * var(--distance));
--y: calc(var(--p-y) * var(--distance));
--scale: calc(1);
}
to {
--x: calc(var(--p-x) * var(--distance));
--y: calc(var(--p-y) * var(--distance));
}
}
@keyframes show {
from {
--x: calc(1dvw * var(--p-r));
--y: calc(-100dvh * var(--p-r));
filter: blur(0.5rem);
--scale: calc(clamp(1.5, 10 * var(--p-r2), 5));
}
5% {
filter: blur(0rem);
}
10% {
--x: calc(var(--p-x) * var(--distance));
--y: calc(var(--p-y) * var(--distance));
--scale: calc(1);
}
to {
--x: calc(var(--p-x) * var(--distance));
--y: calc(var(--p-y) * var(--distance));
}
}
body {
width: 100vw;
height: 100vh;
display: grid;
place-items: center;
background: conic-gradient(at 50% 52%, #180a3e, black, black, #180a3e);
color: #ee75d2;
margin: 0;
overflow: clip;
cursor: pointer;
}
* {
box-sizing: border-box;
}
a.labs-follow-me {
left: 2rem;
right: 2rem;
bottom: 1rem;
top: unset;
text-align: center;
}
</style>
</head>
<body>
<div id="tiles" class="show"></div>
<div id="count" class="content">☠</div>
<canvas id="canvas"></canvas>
<script>
const counts = count.innerText;
const size = 110;
const ctx = canvas.getContext('2d');
const font = `bold ${size}px monospace`;
ctx.font = font;
const metrics = ctx.measureText(counts);
canvas.width = metrics.width;
canvas.height = size;
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.font = font;
ctx.fillStyle = 'black';
ctx.fillText(counts, 0, canvas.height);
const { data } = ctx.getImageData(0, 0, canvas.width, canvas.height);
const length = data.length;
const pixels = [];
let x = 0,
y = 0;
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
for (let i = 0; i < length; i += 4) {
const pixel = {
hit: data[i] !== 255,
i,
x: x - centerX,
y: y - centerY,
};
if (data[i] === 0) {
pixels.push(pixel);
}
x++;
if (x === canvas.width) {
x = 0;
y++;
}
}
pixels.forEach(({ x, y }, index) => {
const tile = document.createElement('div');
tile.style.setProperty('--p-x', `${x}`);
tile.style.setProperty('--p-y', `${y}`);
tile.style.setProperty('--p-i', `${index}`);
tile.style.setProperty('--p-r', `${Math.random()}`);
tile.style.setProperty('--p-r2', `${Math.random()}`);
tiles.appendChild(tile);
});
document.addEventListener('click', () => {
tiles.classList.remove('show');
requestAnimationFrame(() => {
tiles.classList.add('show');
});
});
</script>
</body>
</html>