๐ŸŽ‡ Radial Infographic

BamgasiJMยท2025๋…„ 11์›” 19์ผ

p5.js Art

๋ชฉ๋ก ๋ณด๊ธฐ
27/65
post-thumbnail

๐Ÿ“ Static Version

// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// ์ „์—ญ ๋ณ€์ˆ˜ ์„ ์–ธ (๋ชจ๋“  ํ•จ์ˆ˜์—์„œ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ์„ค์ •๊ฐ’)
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

let numConcentric = 20; // ๋™์‹ฌ์› ๊ฐœ์ˆ˜: 20๊ฐœ
let numRays = 60;       // ๋ฐฉ์‚ฌํ˜• ์„  ๊ฐœ์ˆ˜: 60๊ฐœ
let maxRadius;          // ์ตœ๋Œ€ ๋ฐ˜์ง€๋ฆ„ ๋ณ€์ˆ˜ ์„ค์ •. setup()์—์„œ ์‹ค์ œ ๊ฐ’ ํ• ๋‹น.

// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// setup(): p5.js์˜ ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜. ํ”„๋กœ๊ทธ๋žจ ์‹œ์ž‘ ์‹œ ๋”ฑ ํ•œ ๋ฒˆ ์‹คํ–‰๋จ.
// โ†’ ๋ชจ๋“  ๊ทธ๋ฆผ์„ ์—ฌ๊ธฐ์„œ ํ•œ ๋ฒˆ๋งŒ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค.
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

function setup() {
  // ์บ”๋ฒ„์Šค ํฌ๊ธฐ ์„ค์ •: ๊ฐ€๋กœ 1080px ร— ์„ธ๋กœ 1080px (์ •์‚ฌ๊ฐํ˜•)
  createCanvas(1080, 1080);

  // ์ตœ๋Œ€ ๋ฐ˜์ง€๋ฆ„ ๊ณ„์‚ฐ: ์บ”๋ฒ„์Šค ๊ฐ€๋กœ ๋„ˆ๋น„(width)์˜ 45% โ†’ ์—ฌ๋ฐฑ ํ™•๋ณด (10%๋Š” ํ…Œ๋‘๋ฆฌ ๊ณต๊ฐ„)
  // ์˜ˆ: width=1080 โ†’ maxRadius = 1080 ร— 0.45 = 486px
  maxRadius = width * 0.45;

  // ์บ”๋ฒ„์Šค ์ค‘์‹ฌ ์ขŒํ‘œ โ†’ ๋ฐ˜๋ณต ์‚ฌ์šฉ๋˜๋ฏ€๋กœ ๋ณ€์ˆ˜๋กœ ์ €์žฅ (์ฝ”๋“œ ๊ฐ€๋…์„ฑ โ†‘, ์„ฑ๋Šฅ โ†‘)
  let cx = width / 2; // ์ค‘์‹ฌ x = 1080 / 2 = 540
  let cy = height / 2; // ์ค‘์‹ฌ y = 1080 / 2 = 540

  // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  // ๋ฐฐ๊ฒฝ์ƒ‰ ์„ค์ •: RGB + Alpha (ํˆฌ๋ช…๋„)
  // (40, 30, 40) โ†’ ์ง™์€ ๋ณด๋ผ-๋‚จ์ƒ‰ ๊ณ„์—ด, alpha ์—†์Œ โ†’ ์™„์ „ ๋ถˆํˆฌ๋ช…
  // โ†’ ์ „์ฒด ์บ”๋ฒ„์Šค๋ฅผ ์ด ์ƒ‰์œผ๋กœ ์ฑ„์›€
  // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  background(40, 30, 40);

  // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  // ๋™์‹ฌ์› ๊ทธ๋ฆฌ๊ธฐ
  // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

  // ๋„ํ˜• ๋‚ด๋ถ€๋ฅผ ์น ํ•˜์ง€ ์•Š์Œ (์› ํ…Œ๋‘๋ฆฌ๋งŒ)
  noFill();

  // ์„  ์ƒ‰์ƒ: (R=100, G=90, B=100) โ†’ ํšŒ์ƒ‰ ๊ณ„์—ด์˜ ์—ฐ๋ณด๋ผ, alpha=180 โ†’ ์•ฝ๊ฐ„ ๋ฐ˜ํˆฌ๋ช…
  stroke(100, 90, 100, 180);

  // ์„  ๋‘๊ป˜: 0.5px
  strokeWeight(0.5);

  // ๋™์‹ฌ์› 20๊ฐœ ๋ฐ˜๋ณต ์ƒ์„ฑ: i = 1 ~ 20
  for (let i = 1; i <= numConcentric; i++) {
    // map(๊ฐ’, ์ตœ์†Œ์ž…๋ ฅ, ์ตœ๋Œ€์ž…๋ ฅ, ์ตœ์†Œ์ถœ๋ ฅ, ์ตœ๋Œ€์ถœ๋ ฅ):
    // i๊ฐ€ 1 โ†’ r = 20px, i๊ฐ€ 20 โ†’ r = maxRadius(=486px)๊ฐ€ ๋˜๋„๋ก ๋น„์œจ ๋ณ€ํ™˜
    // โ†’ ์ž‘์€ ์›๋ถ€ํ„ฐ ํฐ ์›๊นŒ์ง€ ๊ท ๋“ฑํ•œ ๊ฐ„๊ฒฉ์œผ๋กœ ๋ฐฐ์น˜
    let r = map(i, 1, numConcentric, 20, maxRadius);

    // circle(์ค‘์‹ฌx, ์ค‘์‹ฌy, ์ง€๋ฆ„) โ†’ ๋ฐ˜์ง€๋ฆ„(r)์˜ 2๋ฐฐ๋ฅผ ์ง€๋ฆ„์œผ๋กœ ์ „๋‹ฌ
    // (p5.js์˜ circle ํ•จ์ˆ˜๋Š” ์ง€๋ฆ„(diameter)์„ ๋ฐ›์Œ, ๋ฐ˜์ง€๋ฆ„(radius) ์•„๋‹˜!)
    circle(cx, cy, r * 2);
  }

  // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  // ์ค‘์‹ฌ๋ถ€ ๊ฐ•์กฐํ•˜๋Š” ์›
  // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

  // ๋„ํ˜• ๋‚ด๋ถ€๋ฅผ ์น ํ•˜์ง€ ์•Š์Œ (์› ํ…Œ๋‘๋ฆฌ๋งŒ)
  noFill();

  // ํฐ์ƒ‰ ๊ณ„์—ด, alpha=120
  stroke(255, 255, 255, 120);

  // ์„  ๋‘๊ป˜๋ฅผ 1.5px๋กœ ์•ฝ๊ฐ„ ๊ฐ•์กฐ
  strokeWeight(1.5);

  // ๊ณ ์ •๋œ ํฌ๊ธฐ(์ง€๋ฆ„ 60px)์˜ ์›์„ ์ค‘์‹ฌ์— ๊ทธ๋ฆผ
  // โ†’ ๋ฐ˜์ง€๋ฆ„ 30px, ์ฆ‰ ์ค‘์‹ฌ์—์„œ 30px ์ด๋‚ด๋Š” ๋น„์›Œ๋‘  (๋‹ค๋ฅธ ์š”์†Œ์™€ ๊ฒน์นจ ๋ฐฉ์ง€)
  circle(cx, cy, 60);

  // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  // ๋ฐฉ์‚ฌํ˜• ์„ (rays)๊ณผ ๊ทธ ์œ„์˜ ์ (circles) ๊ทธ๋ฆฌ๊ธฐ
  // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

  // ์„  ๊ฐœ์ˆ˜(numRays=60)๋งŒํผ ๋ฐ˜๋ณต
  for (let i = 0; i < numRays; i++) {
    // ํ˜„์žฌ ์„ ์˜ ๊ธฐ์ค€ ๊ฐ๋„ ๊ณ„์‚ฐ:
    // i=0 โ†’ 0 rad (โ†’ 0ยฐ), i=59 โ†’ ์•ฝ 6.18 rad (โ†’ 354ยฐ), i=60์ด๋ฉด 2ฯ€(360ยฐ)
    // map(i, 0, 60, 0, TWO_PI) โ†’ 60๋“ฑ๋ถ„๋œ ์›ํ˜• ๋ฐฐ์—ด
    let baseAngle = map(i, 0, numRays, 0, TWO_PI);

    // ์ด ์„ ์˜ ์ „์ฒด ๊ธธ์ด: 30px(์ค‘์‹ฌ ์› ํ…Œ๋‘๋ฆฌ ๋ฐ”๊นฅ) ~ maxRadius(486px) ์‚ฌ์ด ๋žœ๋ค
    // โ†’ ์ค‘์‹ฌ์— ๊ฒน์น˜์ง€ ์•Š๊ณ , ์บ”๋ฒ„์Šค ๋ฐ–์œผ๋กœ ๋‚˜๊ฐ€์ง€๋„ ์•Š์Œ
    let len = random(30, maxRadius);

    // ์„ ์˜ ๋์  ์ขŒํ‘œ ๊ณ„์‚ฐ (์‚ผ๊ฐํ•จ์ˆ˜: x = cosฮธ * r, y = sinฮธ * r)
    let x2 = cx + cos(baseAngle) * len;
    let y2 = cy + sin(baseAngle) * len;

    // โ”€โ”€โ”€โ”€โ”€ ์„  ๊ทธ๋ฆฌ๊ธฐ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

    // ์„  ์ƒ‰์ƒ: (200,200,220), alpha=150
    stroke(200, 200, 220, 150);

    // ์ค‘์‹ฌ(cx,cy)์—์„œ ๋์ (x2,y2)๊นŒ์ง€ ์ง์„  ๊ทธ๋ฆฌ๊ธฐ
    line(cx, cy, x2, y2);

    // โ”€โ”€โ”€โ”€โ”€ ์„  ์œ„์— ์ (circles) ๊ทธ๋ฆฌ๊ธฐ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

    // ์ด ์„  ์œ„์— ๊ทธ๋ฆด ์  ๊ฐœ์ˆ˜: 3~7๊ฐœ ์‚ฌ์ด ๋žœ๋ค (int()๋กœ ์†Œ์ˆ˜์  ๋ฒ„๋ฆผ โ†’ 3,4,5,6,7)
    let steps = int(random(3, 8));

    // ์ ์—๋Š” ์„  ํ…Œ๋‘๋ฆฌ๋ฅผ ๊ทธ๋ฆฌ์ง€ ์•Š์Œ (์ฑ„์šฐ๊ธฐ๋งŒ)
    noStroke();

    // ์ ์„ ์„  ์œ„์— ๊ท ๋“ฑํžˆ ๋ฐฐ์น˜: j = 1 ~ steps
    for (let j = 1; j <= steps; j++) {
      // t = j / (steps + 1):
      // ์˜ˆ: steps=4 โ†’ t = 1/5, 2/5, 3/5, 4/5 โ†’ ์„ ์˜ 20%, 40%, 60%, 80% ์ง€์ 
      // โ†’ ์‹œ์ž‘์ (0)๊ณผ ๋์ (1)์€ ๊ฑด๋„ˆ๋›ฐ์–ด ์ค‘์‹ฌ/๋์— ๊ฒน์น˜์ง€ ์•Š์Œ
      let t = j / (steps + 1);

      // ์ค‘์‹ฌ์œผ๋กœ๋ถ€ํ„ฐ์˜ ์‹ค์ œ ๊ฑฐ๋ฆฌ = ์ „์ฒด ๊ธธ์ด(len) ร— ๋น„์œจ(t)
      let distance = len * t;

      // โš ๏ธ ์ค‘์‹ฌ์—์„œ 30px ์ด๋‚ด๋Š” ๊ฑด๋„ˆ๋œ€ โ†’ ์ค‘์‹ฌ ๊ฐ•์กฐ ์›๊ณผ ๊ฒน์น˜์ง€ ์•Š๊ฒŒ
      if (distance < 30) continue;

      // ์ ์˜ ํฌ๊ธฐ: ์ง€๋ฆ„ 2~8px ์‚ฌ์ด ๋žœ๋ค
      let size = random(2, 8);

      // ์ ์˜ ์ƒ‰์ƒ:
      // random(100) โ†’ 0~100 ์‚ฌ์ด ๋‚œ์ˆ˜, 85๋ณด๋‹ค ํฌ๋ฉด(15% ํ™•๋ฅ ) ๋”ฐ๋œปํ•œ ๋…ธ๋ž€์ƒ‰,
      // ์•„๋‹ˆ๋ฉด(85% ํ™•๋ฅ ) ํฐ์ƒ‰ ๊ณ„์—ด
      let col =
        random(100) > 85
          ? color(220, 180, 80, 200) // ๋…ธ๋ž€์ƒ‰: R=220, G=180, B=80, alpha=200
          : color(240, 240, 240, 180); // ๊ฑฐ์˜ ํฐ์ƒ‰, alpha=180

      // ์ ์˜ ์ ˆ๋Œ€ ์ขŒํ‘œ ๊ณ„์‚ฐ (์ค‘์‹ฌ + ๋ฐฉํ–ฅร—๊ฑฐ๋ฆฌ)
      let px = cx + cos(baseAngle) * distance;
      let py = cy + sin(baseAngle) * distance;

      // ์  ์ƒ‰์ƒ ์ ์šฉ
      fill(col);

      // ์  ๊ทธ๋ฆฌ๊ธฐ: circle(์ค‘์‹ฌx, ์ค‘์‹ฌy, ์ง€๋ฆ„)
      circle(px, py, size);
    }
  }

  // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  // ์ฃผ์„ ํ•ด์ œ ์‹œ ์‹คํ–‰ํ•˜๋ฉด ํŒŒ์ผ ์ €์žฅ
  // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  // save("infographic_style_01.png");
}

function draw() {
  // ์ด ํ•จ์ˆ˜๊ฐ€ ๋น„์–ด ์žˆ์œผ๋ฏ€๋กœ, setup()์—์„œ ๊ทธ๋ฆฐ ์ด๋ฏธ์ง€๊ฐ€ ๊ณ ์ •๋˜์–ด ์œ ์ง€๋จ.
  // ์• ๋‹ˆ๋ฉ”์ด์…˜ ์—†์Œ, CPU ๋ถ€ํ•˜ ์—†์Œ, ์™„์ „ํ•œ ์ •์ง€ ํ™”๋ฉด.
}

๐Ÿ“ Animated Version

let numConcentric = 20;
let numRays = 60;
let maxRadius;
let rotationAngle = 0;
let rayData = []; // ๊ฐ ์„ ์˜ ์ •๋ณด๋ฅผ ์ €์žฅํ•  ๋ฐฐ์—ด

function setup() {
  createCanvas(1080, 1080);
  maxRadius = width * 0.45;

  // ๊ฐ ์„ ์˜ ๋ฐ์ดํ„ฐ ๋ฏธ๋ฆฌ ์ƒ์„ฑ
  for (let i = 0; i < numRays; i++) {
    let baseAngle = map(i, 0, numRays, 0, TWO_PI);
    let len = random(30, maxRadius);

    // ์ด ์„  ์œ„์— ๊ทธ๋ ค์งˆ ์›๋“ค์˜ ์ •๋ณด
    let circles = [];
    let steps = int(random(3, 8));
    for (let j = 1; j <= steps; j++) {
      let t = j / (steps + 1);
      let distance = len * t; // ์ค‘์‹ฌ์œผ๋กœ๋ถ€ํ„ฐ์˜ ๊ฑฐ๋ฆฌ

      // ์ค‘์‹ฌ์—์„œ 30px ์ด๋‚ด๋ฉด ์ œ์™ธ
      if (distance < 30) continue;

      circles.push({
        distance: distance,
        size: random(2, 8),
        color:
          random(100) > 85
            ? color(220, 180, 80, 200)
            : color(240, 240, 240, 180),
      });
    }

    rayData.push({
      baseAngle: baseAngle,
      length: len,
      circles: circles,
    });
  }
}

function draw() {
  background(40, 30, 40);

  // ๋™์‹ฌ์› ๊ทธ๋ฆฌ๊ธฐ
  noFill();
  stroke(100, 90, 100, 180);
  strokeWeight(0.5);
  for (let i = 1; i <= numConcentric; i++) {
    let r = map(i, 1, numConcentric, 20, maxRadius);
    circle(width / 2, height / 2, r * 2);
  }

  // ์ค‘์‹ฌ๋ถ€ ๊ฐ•์กฐ
  noFill();
  stroke(255, 255, 255, 100);
  strokeWeight(1.5);
  circle(width / 2, height / 2, 60);

  // ํšŒ์ „ ๊ฐ๋„ ์—…๋ฐ์ดํŠธ
  rotationAngle = (millis() * 0.05) / 1000;

  let cx = width / 2;
  let cy = height / 2;

  // ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋กœ ์„ ๊ณผ ์› ๊ทธ๋ฆฌ๊ธฐ
  for (let ray of rayData) {
    let angle = ray.baseAngle + rotationAngle;

    // ์„  ๋์  ๊ณ„์‚ฐ
    let x2 = cx + cos(angle) * ray.length;
    let y2 = cy + sin(angle) * ray.length;

    // ์„  ๊ทธ๋ฆฌ๊ธฐ
    stroke(200, 200, 220, 150);
    line(cx, cy, x2, y2);

    // ์›๋“ค ๊ทธ๋ฆฌ๊ธฐ
    noStroke();
    for (let c of ray.circles) {
      let px = cx + cos(angle) * c.distance;
      let py = cy + sin(angle) * c.distance;

      fill(c.color);
      circle(px, py, c.size);
    }
  }
}

๐Ÿ“ ํด๋ž˜์Šค ๋ฌธ๋ฒ• ์‚ฌ์šฉํ•œ Animated Version

// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// ์ „์—ญ ์ƒ์ˆ˜ ๋ฐ ๋ณ€์ˆ˜ ์„ ์–ธ
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

const NUM_RAYS = 60;
const NUM_CONCENTRIC = 20;
const ROTATION_SPEED = 0.0002;
let MAX_RADIUS;
let rays = [];
let concentricCircles;

// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// ConcentricCircles ํด๋ž˜์Šค ์ •์˜
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

class ConcentricCircles {
  constructor(numCircles, maxRadius) {
    this.numCircles = numCircles;
    this.maxRadius = maxRadius;
  }

  draw(centerX, centerY) {
    noFill();

    for (let i = 1; i <= this.numCircles; i++) {
      const radius = map(i, 1, this.numCircles, 20, this.maxRadius);
      const alpha = map(i, 1, this.numCircles, 150, 180);

      stroke(100, 90, 100, alpha);
      strokeWeight(0.5);
      ellipse(centerX, centerY, radius * 2, radius * 2);
    }

    stroke(255, 255, 255, 100);
    strokeWeight(1.5);
    ellipse(centerX, centerY, 60, 60);
  }
}

// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// Ray ํด๋ž˜์Šค ์ •์˜
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

class Ray {
  constructor(baseAngle, maxRadius) {
    this.baseAngle = baseAngle;
    this.length = random(30, maxRadius);
    this.dots = this._createDots();
  }

  _createDots() {
    const dots = [];
    const steps = int(random(3, 8));

    for (let j = 1; j <= steps; j++) {
      const t = j / (steps + 1);
      const distance = this.length * t;

      if (distance < 30) continue;

      dots.push({
        distance: distance,
        size: random(2, 8),
        dotColor:
          random(100) > 85
            ? color(220, 180, 80, 200)
            : color(240, 240, 240, 180),
      });
    }

    return dots;
  }

  draw(centerX, centerY, rotation) {
    const currentAngle = this.baseAngle + rotation;
    const endX = centerX + cos(currentAngle) * this.length;
    const endY = centerY + sin(currentAngle) * this.length;

    stroke(200, 200, 220, 150);
    strokeWeight(1);
    line(centerX, centerY, endX, endY);

    noStroke();
    for (const dot of this.dots) {
      const dotX = centerX + cos(currentAngle) * dot.distance;
      const dotY = centerY + sin(currentAngle) * dot.distance;

      fill(dot.dotColor);
      ellipse(dotX, dotY, dot.size, dot.size);
    }
  }
}

// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// p5.js ๋ฉ”์ธ ํ•จ์ˆ˜
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

function setup() {
  createCanvas(1080, 1080);
  MAX_RADIUS = width * 0.45;

  concentricCircles = new ConcentricCircles(NUM_CONCENTRIC, MAX_RADIUS);

  for (let i = 0; i < NUM_RAYS; i++) {
    const angle = map(i, 0, NUM_RAYS, 0, TWO_PI);
    rays.push(new Ray(angle, MAX_RADIUS));
  }

  frameRate(60);
}

function draw() {
  background(40, 30, 40);

  const currentRotation = millis() * ROTATION_SPEED;
  const centerX = width / 2;
  const centerY = height / 2;

  concentricCircles.draw(centerX, centerY);

  for (const ray of rays) {
    ray.draw(centerX, centerY, currentRotation);
  }
}

profile
Coding Art with Blender / oF / Processing / p5.js / nannou

0๊ฐœ์˜ ๋Œ“๊ธ€