나… 나도 할꺼야 움짤아이콘!! [13]

맨밑
퍼플히아신스
아바타/쪽지/글검색

2025-04-24 21:11:28
3 0 13 75

ⓞ 추천  ⓤ 단축URL
↑ 복사 후 붙여넣으세요.
 기기를 감지하여 최적 URL 로 보내줍니다.
퍼플히아신스
https://humoruniv.com/pdswait11615335 URL 복사
36KB

바뀌었낭

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>

* 컨텐츠 출처 : 작성자 본인

ⓞ 게 시 물    추 천 하 기
  로그인 없이 추천가능합니다.
추천되었습니다.
ⓞ 추천   ⓧ 반대   ⓡ 답글   ▤ 목록
← 뒤로   ↑ 맨위   ↓ 맨밑   ㉦ 신고   ♡ 스크랩
← 뒤로   ↑ 맨위   ↓ 맨밑   ㉦ 신고   ♡ 스크랩
답글 작성하기 (로그인 필요)
로그인   메인   사이트맵   PC화면