¹Ù²î¾ú³¶
html canvas·Î ±×·È´Âµ¥. êÁöÇÇÆ¼ÇÑÅ× ÇØ´Þ¶ó ÇÏ´Ï±î ¿Í ¶ÒµüÀ̳×.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>¡Ù ÆÛÇÃÀÌ ¾ÆÀÌÄÜ ¡Ù</title>
<link href="https://fonts.googleapis.com/css2?family=Nanum+Gothic&display=swap" rel="stylesheet">
<style>
@font-face {
font-family: 'SeoulHangangM';
src: url£¨'https://fastly.jsdelivr.net/gh/projectnoonnu/noonfonts_two@1.0/SeoulHangangM.woff'£© format£¨'woff'£©;
font-weight: normal;
font-style: normal;
}
body {
margin: 0;
background: white;
overflow: hidden;
}
canvas {
display: block;
margin: auto;
/* width: 25px;
height: 25px;*/
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
const ANI_SPEED_RATE = 1;
const CANVAS_SIZE = 100;
const TRIANGLE_NUM = 50;
const TRIANGLE_INTERVAL = 30;
const TRIANGLE_MAX_SIZE = 120;
const TRIANGLE_DURATION = 800;
const TEXT_START_TIME = 700;
const TEXT = "ÆÛÇÃÈ÷¾Æ½Å½º";
const TEXT_SPEED = 4;
const TEXT_SIZE = 0.7;
const TEXT_FONT = "SeoulHangangM";
const TEXT_COLOR_1 = "white";
const TEXT_COLOR_2 = "#56f";
const canvas = document.getElementById£¨"canvas"£©;
const ctx = canvas.getContext£¨"2d"£©;
canvas.width = CANVAS_SIZE;
canvas.height = CANVAS_SIZE;
const COLORS = [
[96, 16, 255, 1],
[32, 0, 255, 1],
[80, 0, 0, 1],
[96, 0, 0, 0.5],
[255, 0, 0, 0.01]
];
const totalPhases = COLORS.length - 1;
function lerp£¨a, b, t£© {
return a + £¨b - a£© * t;
}
function lerpColor£¨c1, c2, t£© {
return [
Math.floor£¨lerp£¨c1[0], c2[0], t£©£©,
Math.floor£¨lerp£¨c1[1], c2[1], t£©£©,
Math.floor£¨lerp£¨c1[2], c2[2], t£©£©,
lerp£¨c1[3], c2[3], t£©
];
}
function rgbaToString£¨rgba£© {
return `rgba£¨${rgba[0]}, ${rgba[1]}, ${rgba[2]}, ${rgba[3]}£©`;
}
function generateRandomTriangle£¨x, y, range = TRIANGLE_MAX_SIZE£© {
return Array.from£¨{ length: 3 }, £¨£© => £¨{
x: x + Math.random£¨£© * range,
y: y + Math.random£¨£© * range
}£©£©;
}
function drawTriangle£¨points, color£© {
ctx.beginPath£¨£©;
ctx.moveTo£¨points[0].x, points[0].y£©;
ctx.lineTo£¨points[1].x, points[1].y£©;
ctx.lineTo£¨points[2].x, points[2].y£©;
ctx.closePath£¨£©;
ctx.fillStyle = color;
ctx.fill£¨£©;
}
const triangles = [];
class AnimatedTriangle {
c o n s - t r u c t o r£¨points£© {
this.points = points;
this.startTime = performance.now£¨£©;
}
updateAndDraw£¨now£© {
const elapsed = £¨ now - this.startTime £© * ANI_SPEED_RATE;
const currentPhase = Math.floor£¨elapsed / TRIANGLE_DURATION£©;
if £¨currentPhase >= totalPhases£© return false;
const phaseProgress = £¨elapsed % TRIANGLE_DURATION£© / TRIANGLE_DURATION;
const from = COLORS[currentPhase];
const to = COLORS[currentPhase + 1];
const currentColor = lerpColor£¨from, to, phaseProgress£©;
drawTriangle£¨this.points, rgbaToString£¨currentColor£©£©;
return true;
}
}
let allTrianglesSpawned = false;
let textStartTime = null;
setTimeout£¨£¨£© => {
textStartTime = performance.now£¨£©;
}, TEXT_START_TIME / ANI_SPEED_RATE£©;
function animateAll£¨£© {
const now = performance.now£¨£©;
ctx.clearRect£¨0, 0, canvas.width, canvas.height£©;
ctx.fillStyle = "black";
ctx.fillRect£¨0, 0, canvas.width, canvas.height£©;
ctx.globalCompositeOperation = "lighter";
for £¨let i = triangles.length - 1; i >= 0; i--£© {
const stillVisible = triangles[i].updateAndDraw£¨now£©;
if £¨!stillVisible£© {
triangles.splice£¨i, 1£©;
}
}
if £¨textStartTime !== null£© {
const timeSinceStart = now - textStartTime;
const t = timeSinceStart * ANI_SPEED_RATE;
const x = canvas.width + 50 - TEXT_SPEED / 16 * t;
ctx.font = `${canvas.height * TEXT_SIZE}px "${TEXT_FONT}"`;
ctx.textBaseline = "middle";
ctx.textAlign = "left";
ctx.fillStyle = TEXT_COLOR_2;
ctx.fillText£¨TEXT, x+6, canvas.height / 2£©;
ctx.fillStyle = TEXT_COLOR_1;
ctx.fillText£¨TEXT, x, canvas.height / 2£©;
}
requestAnimationFrame£¨animateAll£©;
}
function spawnTriangles£¨£© {
let count = 0;
const interval = setInterval£¨£¨£© => {
if £¨count >= TRIANGLE_NUM£© {
clearInterval£¨interval£©;
allTrianglesSpawned = true;
return;
}
const x = Math.random£¨£© * £¨canvas.width + TRIANGLE_MAX_SIZE£© - TRIANGLE_MAX_SIZE/2;
const y = Math.random£¨£© * £¨canvas.height + TRIANGLE_MAX_SIZE£© - TRIANGLE_MAX_SIZE/2;
const points = generateRandomTriangle£¨x, y£©;
triangles.push£¨ new AnimatedTriangle£¨points£© £©;
count++;
}, TRIANGLE_INTERVAL / ANI_SPEED_RATE£©;
}
animateAll£¨£©;
spawnTriangles£¨£©;
</script>
</body>
</html>