쪽지발송 성공
Click here
재능넷 이용방법
재능넷 이용방법 동영상편
가입인사 이벤트
판매 수수료 안내
안전거래 TIP
재능인 인증서 발급안내

홈페이지 유지보수(수정) 및 제작 해드립니다.ASP, PHP, MSSQL, MYSQL, jQuery, Javascript, 각종 API연동 등홈페이지(웹/모바일) 개발 및 디자인 ...

안녕하세요.저는 현업 9년차 IT 서비스 중견기업에 재직중인 개발자입니다.결과물만 중요하게 생각하지 않고, 소스코드와 개발 과정 그리고 완성도...

 기본 작업은 사이트의 기능수정입니다.호스팅에 보드 설치 및 셋팅. (그누, 제로, 워드, 기타 cafe24,고도몰 등)그리고 각 보드의 대표적인 ...

10년차 php 프로그래머 입니다. 그누보드, 영카트 외 php로 된 솔루션들 커스터마이징이나 오류수정 등 유지보수 작업이나신규개발도 가능합...

Ver2.0 CSS 후디니 페인트 API로 내 웹사이트를 힙하게 꾸미기: 나만의 커스텀 배경 패턴 만들기 🎨
재능넷
댓글수 0

CSS 후디니 페인트 API로 내 웹사이트를 힙하게 꾸미기: 나만의 커스텀 배경 패턴 만들기 🎨

콘텐츠 대표 이미지 - CSS 후디니 페인트 API로 내 웹사이트를 힙하게 꾸미기: 나만의 커스텀 배경 패턴 만들기 🎨

 

 

안녕하세요, 웹 개발 덕후 여러분! 😎 오늘은 CSS의 숨겨진 보석 같은 기능, 후디니 페인트 API에 대해 함께 알아볼게요. 2025년 현재 웹 개발 트렌드에서 빠질 수 없는 이 기술로 여러분의 웹사이트에 독특한 배경 패턴을 적용하는 방법을 알려드릴게요. 이 글을 읽고 나면 여러분도 재능넷 같은 멋진 플랫폼에서 자랑할 수 있는 CSS 커스텀 디자인 스킬을 갖추게 될 거예요! 자, 그럼 시작해볼까요? 🚀

후디니가 뭐길래? 🤔 CSS의 마법사를 소개합니다

CSS 후디니(Houdini)라는 이름 들어보셨나요? 마술사 해리 후디니처럼 CSS에 마법 같은 기능을 부여한다고 해서 붙여진 이름인데요, 진짜 웹 개발의 게임 체인저라고 할 수 있어요! ✨

간단히 말하자면, 후디니는 브라우저의 렌더링 엔진에 직접 접근할 수 있게 해주는 API 모음집이에요. 이전까지 개발자들은 CSS의 한계 내에서만 디자인을 구현해야 했지만, 후디니는 그 한계를 확 넓혀주는 마법 지팡이 같은 존재죠.

특히 오늘 집중적으로 알아볼 페인트 API(Paint API)는 후디니의 핵심 기능 중 하나로, 개발자가 직접 CSS 속성의 시각적 출력을 제어할 수 있게 해줍니다. 쉽게 말해서 "CSS로 그림 그리기"가 가능해진 거예요! 🎭

"CSS 후디니는 웹 개발자에게 슈퍼파워를 주는 것과 같습니다. 이제 CSS만으로도 상상하는 모든 디자인을 구현할 수 있어요."

- 어느 행복한 웹 개발자 -

CSS Paint API Layout API Animation API CSS 후디니: 브라우저 렌더링 엔진의 마법사 웹 디자인의 한계를 넘어서는 혁신적인 API 세트

후디니의 등장 배경을 간단히 살펴볼까요? 웹 개발자들은 오랫동안 CSS의 한계에 좌절해왔어요. "이것도 CSS로 할 수 있으면 얼마나 좋을까?" 하는 생각, 다들 한 번쯤 해보셨죠? 🤦‍♀️

그래서 구글을 중심으로 한 개발자 그룹이 "그럼 우리가 만들자!"라는 생각으로 후디니 프로젝트를 시작했어요. 2025년 현재, 후디니 API는 대부분의 모던 브라우저에서 지원되고 있으며, 특히 페인트 API는 크롬, 엣지, 파이어폭스 등 주요 브라우저에서 안정적으로 사용할 수 있게 되었답니다.

페인트 API의 기본 개념 💡 이해하기 쉽게 설명해드릴게요

자, 이제 본격적으로 페인트 API에 대해 알아볼까요? 페인트 API는 개발자가 CSS의 paint() 함수를 통해 자바스크립트로 그래픽을 그릴 수 있게 해주는 기능이에요. 캔버스 API와 비슷하다고 생각하시면 이해가 쉬울 거예요! 🖌️

페인트 API의 핵심 개념

  1. 페인트 워크렛(Paint Worklet): 자바스크립트로 작성된 그래픽 모듈로, CSS에서 호출할 수 있어요.

  2. paint() 함수: CSS 내에서 커스텀 페인트 워크렛을 호출하는 함수예요.

  3. registerPaint(): 새로운 페인트 워크렛을 등록하는 자바스크립트 메서드예요.

  4. paint() 메서드: 워크렛 내에서 실제 그래픽을 그리는 메서드로, Canvas API와 유사한 문법을 사용해요.

페인트 API를 사용하면 CSS 속성값으로 동적인 그래픽을 생성할 수 있어요. 예를 들어, background-image: paint(myPattern);처럼 사용하면 'myPattern'이라는 이름의 페인트 워크렛이 배경 이미지를 그려줍니다.

이게 왜 혁신적이냐고요? 기존에는 복잡한 패턴을 만들려면 이미지 파일을 사용하거나 복잡한 CSS 트릭을 써야 했어요. 하지만 페인트 API를 사용하면:

  1. 동적으로 변하는 패턴을 만들 수 있어요 (사용자 입력이나 시간에 따라 변화 가능)

  2. 추가 이미지 파일 없이 가벼운 코드만으로 복잡한 그래픽 구현 가능

  3. CSS 변수와 연동해 쉽게 커스터마이징 가능

  4. 브라우저 렌더링 엔진 레벨에서 최적화되어 성능이 좋음

간단한 예시를 통해 페인트 API의 기본 구조를 살펴볼게요:

1. 페인트 워크렛 정의하기 (JavaScript)

// myPattern.js
class MyPattern {
  paint(ctx, size, properties) {
    // Canvas API와 유사한 그리기 코드
    ctx.fillStyle = 'purple';
    ctx.fillRect(0, 0, size.width, size.height);
    
    // 원 그리기
    ctx.fillStyle = 'gold';
    ctx.beginPath();
    ctx.arc(size.width/2, size.height/2, 50, 0, 2 * Math.PI);
    ctx.fill();
  }
}

// 워크렛 등록
registerPaint('myPattern', MyPattern);

2. 워크렛 로드하기 (JavaScript)

// 메인 JavaScript 파일에서
if ('paintWorklet' in CSS) {
  CSS.paintWorklet.addModule('myPattern.js');
}

3. CSS에서 사용하기

.my-element {
  background-image: paint(myPattern);
  width: 200px;
  height: 200px;
}

위 코드를 실행하면 보라색 배경에 금색 원이 그려진 요소가 생성됩니다. 꽤 간단하죠? 이게 페인트 API의 기본 사용법이에요! 😄

class MyPattern { paint(ctx, size, props) { ctx.fillStyle = 'purple'; ctx.fillRect(0, 0, size.width, size.height); ctx.fillStyle = 'gold'; ctx.beginPath(); ctx.arc(size.width/2, size.height/2, 50, 0, 2*Math.PI); ctx.fill(); } } 실행 결과 페인트 워크렛 코드 .my-element { background-image: paint(myPattern); }

페인트 API의 진짜 매력은 CSS 변수(Custom Properties)와 함께 사용할 때 빛을 발해요. CSS 변수를 통해 JavaScript 없이도 페인트 워크렛의 동작을 제어할 수 있거든요! 이건 나중에 더 자세히 알아볼게요. 일단 기본 개념은 이해되셨죠? 🙌

2025년 브라우저 지원 현황 🌐 어디서 쓸 수 있을까?

페인트 API를 실제 프로젝트에 적용하기 전에 브라우저 지원 현황을 확인해볼까요? 2025년 3월 현재 상황을 정리해봤어요!

CSS 페인트 API 브라우저 지원 현황 (2025년 3월 기준)

  1. Chrome: 완전 지원 (버전 65부터)

  2. Edge: 완전 지원 (Chromium 기반 전환 이후)

  3. Firefox: 완전 지원 (2024년 말부터)

  4. Safari: 부분 지원 (최신 버전에서 flag 활성화 필요)

  5. Opera: 완전 지원 (Chromium 기반)

  6. Samsung Internet: 완전 지원

  7. 모바일 브라우저: Android Chrome, iOS Safari 최신 버전에서 지원

와우! 2025년에는 대부분의 주요 브라우저에서 페인트 API를 사용할 수 있게 되었네요. 2023년까지만 해도 Firefox와 Safari에서 지원이 제한적이었는데, 이제는 거의 모든 브라우저에서 사용 가능해졌어요. 특히 Firefox가 2024년 말부터 완전 지원을 시작한 건 웹 개발자들에게 정말 반가운 소식이죠! 🎉

하지만 아직 Safari에서는 약간의 제한이 있으니, 폴리필(polyfill)이나 대체 방안을 준비해두는 것이 좋아요. 다행히 CSS의 @supports 규칙을 사용하면 페인트 API를 지원하지 않는 브라우저에 대한 대체 스타일을 쉽게 제공할 수 있답니다.

/* 페인트 API 지원 여부 확인 */
@supports (background: paint(id)) {
  .my-element {
    background-image: paint(myPattern);
  }
}

/* 페인트 API를 지원하지 않는 브라우저용 대체 스타일 */
@supports not (background: paint(id)) {
  .my-element {
    background-image: linear-gradient(purple, darkpurple);
  }
}

이렇게 하면 페인트 API를 지원하지 않는 브라우저에서도 사용자 경험을 해치지 않고 적절한 대체 디자인을 제공할 수 있어요. 똑똑하죠? 😏

CSS 페인트 API 브라우저 지원 현황 (2025) Chrome 100% Edge 100% Firefox 95% Safari 70% Opera 100% 완전 지원 부분 지원 미지원

재능넷 같은 웹 플랫폼을 개발할 때도 이런 브라우저 호환성을 고려하는 게 중요해요. 사용자들이 어떤 브라우저를 사용하든 일관된 경험을 제공할 수 있으니까요! 🌈

이제 기본 개념과 브라우저 지원 현황을 알았으니, 실제로 멋진 배경 패턴을 만드는 방법을 알아볼까요?

나만의 커스텀 배경 패턴 만들기 ✨ 실전 예제

드디어 재미있는 파트가 왔어요! 이제 페인트 API를 사용해서 실제로 멋진 배경 패턴을 만들어볼게요. 여러 가지 예제를 통해 단계별로 알아봅시다! 🎮

1. 기본 도트 패턴 만들기

가장 먼저 간단한 도트 패턴부터 시작해볼게요. 이 패턴은 배경에 균일하게 분포된 원형 도트를 그려줍니다.

도트 패턴 워크렛 (dotPattern.js)

class DotPattern {
  static get inputProperties() {
    return [
      '--dot-color',
      '--dot-size',
      '--dot-spacing'
    ];
  }

  paint(ctx, size, properties) {
    // CSS 변수에서 값 가져오기
    const dotColor = properties.get('--dot-color').toString() || 'black';
    const dotSize = parseInt(properties.get('--dot-size').toString()) || 10;
    const dotSpacing = parseInt(properties.get('--dot-spacing').toString()) || 20;
    
    // 캔버스 전체에 도트 그리기
    for (let x = dotSpacing/2; x < size.width; x += dotSpacing) {
      for (let y = dotSpacing/2; y < size.height; y += dotSpacing) {
        ctx.fillStyle = dotColor;
        ctx.beginPath();
        ctx.arc(x, y, dotSize/2, 0, 2 * Math.PI);
        ctx.fill();
      }
    }
  }
}

registerPaint('dotPattern', DotPattern);

HTML에서 사용하기

<div class="dot-background">
  여기에 내용이 들어갑니다!
</div>

CSS에서 적용하기

.dot-background {
  --dot-color: #3498db;
  --dot-size: 8;
  --dot-spacing: 24;
  background-image: paint(dotPattern);
  padding: 20px;
  color: white;
  min-height: 200px;
}

위 코드를 적용하면 파란색 도트가 규칙적으로 배열된 배경이 생성됩니다. CSS 변수를 통해 도트의 색상, 크기, 간격을 쉽게 조절할 수 있어요. 이게 페인트 API의 강력한 점이죠! 😎

2. 물결 패턴 만들기

이번에는 조금 더 동적인 느낌의 물결(웨이브) 패턴을 만들어볼게요. 사인 함수를 사용해 부드러운 곡선을 그릴 거예요.

물결 패턴 워크렛 (wavePattern.js)

class WavePattern {
  static get inputProperties() {
    return [
      '--wave-color',
      '--wave-amplitude',
      '--wave-frequency',
      '--wave-phase'
    ];
  }

  paint(ctx, size, properties) {
    // CSS 변수에서 값 가져오기
    const waveColor = properties.get('--wave-color').toString() || '#ff7675';
    const amplitude = parseInt(properties.get('--wave-amplitude').toString()) || 20;
    const frequency = parseFloat(properties.get('--wave-frequency').toString()) || 0.02;
    const phase = parseFloat(properties.get('--wave-phase').toString()) || 0;
    
    const height = size.height;
    const width = size.width;
    
    // 배경 채우기
    ctx.fillStyle = 'transparent';
    ctx.fillRect(0, 0, width, height);
    
    // 물결 그리기
    ctx.fillStyle = waveColor;
    ctx.beginPath();
    
    // 시작점 (왼쪽 하단)
    ctx.moveTo(0, height);
    
    // 물결 곡선 그리기
    for (let x = 0; x <= width; x++) {
      // 사인 함수로 y 좌표 계산
      const y = height/2 + amplitude * Math.sin(frequency * x + phase);
      ctx.lineTo(x, y);
    }
    
    // 오른쪽 하단과 왼쪽 하단을 연결해 도형 완성
    ctx.lineTo(width, height);
    ctx.lineTo(0, height);
    ctx.closePath();
    ctx.fill();
  }
}

registerPaint('wavePattern', WavePattern);

CSS에서 적용하기

.wave-background {
  --wave-color: rgba(52, 152, 219, 0.7);
  --wave-amplitude: 30;
  --wave-frequency: 0.015;
  --wave-phase: 0;
  background-image: paint(wavePattern);
  min-height: 300px;
  position: relative;
}

/* 애니메이션 효과 추가 */
@keyframes wave-animation {
  0% { --wave-phase: 0; }
  100% { --wave-phase: 6.28; } /* 2π */
}

.animated-wave {
  animation: wave-animation 4s infinite linear;
}

이 코드는 물결 모양의 배경을 생성하고, CSS 애니메이션을 통해 물결이 움직이는 효과까지 줄 수 있어요. CSS 애니메이션과 페인트 API의 조합으로 정적인 이미지로는 구현하기 어려운 효과를 만들 수 있답니다! 🌊

도트 패턴 물결 패턴 // 페인트 API의 핵심 구조 class MyPattern { static get inputProperties() { return ['--my-variable']; } paint(ctx, size, properties) { /* 그래픽 그리기 코드 */ } }

3. 컨페티(색종이) 패턴 만들기

이번에는 좀 더 재미있는 컨페티(색종이) 패턴을 만들어볼게요. 랜덤하게 분포된 다양한 색상의 작은 사각형과 원을 그려서 축하하는 느낌의 배경을 만들 거예요.

컨페티 패턴 워크렛 (confettiPattern.js)

class ConfettiPattern {
  static get inputProperties() {
    return [
      '--confetti-density',
      '--confetti-size-max'
    ];
  }

  paint(ctx, size, properties) {
    const density = parseInt(properties.get('--confetti-density').toString()) || 100;
    const maxSize = parseInt(properties.get('--confetti-size-max').toString()) || 10;
    
    // 컨페티 색상 배열
    const colors = [
      '#ff7675', '#74b9ff', '#55efc4', '#ffeaa7', 
      '#a29bfe', '#fd79a8', '#00cec9', '#fdcb6e'
    ];
    
    // 랜덤 컨페티 그리기
    for (let i = 0; i < density; i++) {
      // 랜덤 위치
      const x = Math.random() * size.width;
      const y = Math.random() * size.height;
      
      // 랜덤 크기
      const confettiSize = Math.random() * maxSize + 2;
      
      // 랜덤 색상
      const color = colors[Math.floor(Math.random() * colors.length)];
      
      // 랜덤 모양 (원 또는 사각형)
      const isCircle = Math.random() > 0.5;
      
      ctx.fillStyle = color;
      
      if (isCircle) {
        ctx.beginPath();
        ctx.arc(x, y, confettiSize / 2, 0, 2 * Math.PI);
        ctx.fill();
      } else {
        // 랜덤 회전
        const rotation = Math.random() * Math.PI;
        
        ctx.save();
        ctx.translate(x, y);
        ctx.rotate(rotation);
        ctx.fillRect(-confettiSize/2, -confettiSize/2, confettiSize, confettiSize);
        ctx.restore();
      }
    }
  }
}

registerPaint('confettiPattern', ConfettiPattern);

CSS에서 적용하기

.confetti-background {
  --confetti-density: 150;
  --confetti-size-max: 8;
  background-image: paint(confettiPattern);
  background-color: white;
  min-height: 300px;
  padding: 20px;
}

이 코드는 랜덤한 위치, 크기, 색상, 모양의 컨페티를 생성해 축하하는 분위기의 배경을 만들어줍니다. CSS 변수로 컨페티의 밀도와 최대 크기를 조절할 수 있어요. 이런 랜덤한 패턴은 일반 CSS로는 구현하기 매우 어렵죠! 🎉

위의 세 가지 예제를 통해 페인트 API로 다양한 배경 패턴을 만드는 방법을 알아봤어요. 이제 이런 패턴들을 실제 웹사이트에 적용하는 방법을 알아볼까요?

실제 웹사이트에 적용하기 🚀 활용 사례와 팁

이론은 충분히 배웠으니, 이제 페인트 API를 실제 웹사이트에 어떻게 적용할 수 있는지 알아볼게요! 여러 활용 사례와 실전 팁을 소개해드릴게요. 🛠️

1. 헤더 배경으로 활용하기

웹사이트의 헤더는 첫인상을 결정하는 중요한 요소예요. 페인트 API로 만든 독특한 배경 패턴을 헤더에 적용하면 사이트의 개성을 드러낼 수 있어요.

헤더에 물결 패턴 적용하기

header {
  --wave-color: rgba(41, 128, 185, 0.7);
  --wave-amplitude: 20;
  --wave-frequency: 0.02;
  --wave-phase: 0;
  background-image: paint(wavePattern);
  padding: 2rem;
  color: white;
  position: relative;
}

/* 헤더 내용이 잘 보이도록 오버레이 추가 */
header::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: linear-gradient(to right, rgba(0,0,0,0.7), rgba(0,0,0,0.3));
  z-index: 1;
}

header > * {
  position: relative;
  z-index: 2;
}

이렇게 하면 물결 패턴 위에 그라데이션 오버레이를 추가해 텍스트가 잘 보이도록 할 수 있어요. 헤더에 동적인 느낌을 주면서도 가독성을 유지하는 방법이죠! 👍

2. 섹션 구분 요소로 활용하기

긴 웹페이지에서 섹션을 구분할 때 페인트 API로 만든 패턴을 활용하면 시각적 흥미를 더할 수 있어요.

섹션 구분선에 도트 패턴 적용하기

.section-divider {
  --dot-color: #e74c3c;
  --dot-size: 4;
  --dot-spacing: 12;
  height: 60px;
  background-image: paint(dotPattern);
  margin: 2rem 0;
  border-radius: 30px;
}

이렇게 하면 단순한 구분선 대신 시각적으로 흥미로운 요소를 추가할 수 있어요. 사용자의 시선을 끌면서도 페이지의 구조를 명확히 하는 효과가 있죠! 👀

3. 카드나 컴포넌트 배경으로 활용하기

블로그 포스트, 제품 카드, 가격표 등 다양한 컴포넌트의 배경으로 페인트 API 패턴을 활용할 수 있어요.

프로필 카드에 컨페티 패턴 적용하기

.profile-card {
  --confetti-density: 80;
  --confetti-size-max: 5;
  background-image: paint(confettiPattern);
  background-color: white;
  border-radius: 10px;
  box-shadow: 0 4px 6px rgba(0,0,0,0.1);
  padding: 1.5rem;
  margin-bottom: 1rem;
  transition: transform 0.3s ease;
}

.profile-card:hover {
  transform: translateY(-5px);
}

이렇게 하면 프로필 카드에 축하하는 느낌의 배경을 추가할 수 있어요. 특별한 이벤트나 성취를 축하하는 컴포넌트에 적합한 디자인이죠! 🎊

웹사이트 헤더 페인트 API로 만든 물결 패턴 배경 섹션 구분선 프로필 홍길동 웹 개발자 컨페티 패턴 배경의 프로필 카드 페인트 API 활용 팁 1. 헤더 배경으로 물결 패턴 사용 2. 섹션 구분선에 도트 패턴 적용 3. 카드 컴포넌트에 컨페티 패턴 활용 4. 호버 효과와 애니메이션 결합 5. CSS 변수로 패턴 커스터마이징 6. 폴백 스타일 제공하기

4. 인터랙티브 요소 만들기

페인트 API와 CSS 변수를 결합하면 사용자 상호작용에 반응하는 인터랙티브한 배경을 만들 수 있어요.

호버 시 변화하는 물결 패턴

.interactive-wave {
  --wave-color: rgba(52, 152, 219, 0.5);
  --wave-amplitude: 20;
  --wave-frequency: 0.02;
  --wave-phase: 0;
  background-image: paint(wavePattern);
  transition: --wave-amplitude 0.3s ease, --wave-color 0.3s ease;
}

.interactive-wave:hover {
  --wave-amplitude: 40;
  --wave-color: rgba(155, 89, 182, 0.7);
}

이 코드는 요소에 마우스를 올리면 물결의 진폭이 커지고 색상이 변하는 효과를 줍니다. CSS 변수의 트랜지션과 페인트 API를 결합해 인터랙티브한 경험을 만들 수 있어요! 🖱️

5. 실전 팁과 주의사항

페인트 API를 실제 프로젝트에 적용할 때 알아두면 좋은 팁들을 모아봤어요:

  1. 성능 최적화: 복잡한 그래픽은 성능에 영향을 줄 수 있어요. 특히 모바일 기기에서는 간단한 패턴을 사용하는 것이 좋아요.

  2. 폴백 제공하기: @supports 규칙을 사용해 페인트 API를 지원하지 않는 브라우저에 대체 스타일을 제공하세요.

  3. 워크렛 로딩 최적화: 페인트 워크렛은 비동기적으로 로드되므로, 초기 렌더링 시 깜빡임을 방지하기 위한 대체 스타일을 제공하세요.

  4. CSS 변수 활용: 패턴의 모든 속성을 CSS 변수로 제어하면 JavaScript 없이도 다양한 변화를 줄 수 있어요.

  5. 디버깅: 페인트 API 디버깅은 쉽지 않을 수 있어요. console.log가 워크렛 내에서 작동하지 않으므로 단계별로 테스트하세요.

💡 프로 팁

재능넷 같은 웹 플랫폼을 개발할 때는 페인트 API를 사용자 프로필 배경이나 성취 배지 등에 적용해보세요. 사용자의 활동이나 성취에 따라 동적으로 변하는 배경을 만들면 사용자 경험을 크게 향상시킬 수 있어요!

이제 페인트 API를 실제 웹사이트에 적용하는 방법을 알게 되었어요. 다음으로는 더 복잡한 패턴을 만들기 위한 고급 기법을 알아볼게요!

고급 기법: 더 멋진 패턴 만들기 🔥

기본적인 패턴 만들기는 이제 마스터했으니, 한 단계 더 나아가 볼까요? 좀 더 복잡하고 멋진 패턴을 만들기 위한 고급 기법들을 소개해드릴게요! 😎

1. 수학 함수를 활용한 복잡한 패턴

수학 함수를 활용하면 정말 아름다운 패턴을 만들 수 있어요. 사인, 코사인 같은 삼각함수부터 복잡한 수학 공식까지, 다양한 수학적 접근으로 독특한 패턴을 만들어봅시다.

리사주 곡선(Lissajous Curve) 패턴

class LissajousPattern {
  static get inputProperties() {
    return [
      '--lissajous-a',
      '--lissajous-b',
      '--lissajous-delta',
      '--lissajous-color',
      '--lissajous-line-width'
    ];
  }

  paint(ctx, size, properties) {
    // 파라미터 가져오기
    const a = parseFloat(properties.get('--lissajous-a').toString()) || 3;
    const b = parseFloat(properties.get('--lissajous-b').toString()) || 2;
    const delta = parseFloat(properties.get('--lissajous-delta').toString()) || Math.PI / 2;
    const color = properties.get('--lissajous-color').toString() || '#3498db';
    const lineWidth = parseInt(properties.get('--lissajous-line-width').toString()) || 2;
    
    const width = size.width;
    const height = size.height;
    const centerX = width / 2;
    const centerY = height / 2;
    const radius = Math.min(width, height) / 2.5;
    
    // 리사주 곡선 그리기
    ctx.strokeStyle = color;
    ctx.lineWidth = lineWidth;
    ctx.beginPath();
    
    for (let t = 0; t < 2 * Math.PI; t += 0.01) {
      const x = centerX + radius * Math.sin(a * t + delta);
      const y = centerY + radius * Math.sin(b * t);
      
      if (t === 0) {
        ctx.moveTo(x, y);
      } else {
        ctx.lineTo(x, y);
      }
    }
    
    ctx.stroke();
  }
}

registerPaint('lissajousPattern', LissajousPattern);

CSS에서 적용하기

.lissajous-background {
  --lissajous-a: 3;
  --lissajous-b: 2;
  --lissajous-delta: 1.57079632679; /* π/2 */
  --lissajous-color: #3498db;
  --lissajous-line-width: 2;
  background-image: paint(lissajousPattern);
  background-color: #f8f9fa;
  min-height: 300px;
}

이 코드는 리사주 곡선이라는 수학적 곡선을 그려줍니다. a, b, delta 값을 변경하면 다양한 모양의 곡선을 만들 수 있어요. 수학적 공식을 활용해 아름다운 패턴을 만드는 좋은 예시죠! 📐

2. 랜덤성과 시드(Seed) 활용하기

완전한 랜덤보다는 시드 기반의 의사 랜덤(pseudo-random)을 활용하면 일관된 패턴을 만들 수 있어요. 이는 새로고침해도 동일한 패턴을 유지하고 싶을 때 유용합니다.

시드 기반 랜덤 패턴

class SeededRandomPattern {
  // 시드 기반 랜덤 함수
  seededRandom(seed) {
    let t = seed + 0x6D2B79F5;
    t = Math.imul(t ^ t >>> 15, t | 1);
    t ^= t + Math.imul(t ^ t >>> 7, t | 61);
    return ((t ^ t >>> 14) >>> 0) / 4294967296;
  }
  
  static get inputProperties() {
    return [
      '--pattern-seed',
      '--pattern-density',
      '--pattern-color'
    ];
  }

  paint(ctx, size, properties) {
    const seed = parseInt(properties.get('--pattern-seed').toString()) || 12345;
    const density = parseInt(properties.get('--pattern-density').toString()) || 100;
    const color = properties.get('--pattern-color').toString() || '#3498db';
    
    const width = size.width;
    const height = size.height;
    
    ctx.fillStyle = color;
    
    // 시드 기반으로 일관된 랜덤 패턴 생성
    for (let i = 0; i < density; i++) {
      const x = this.seededRandom(seed + i * 2) * width;
      const y = this.seededRandom(seed + i * 2 + 1) * height;
      const radius = this.seededRandom(seed + i * 2 + 2) * 5 + 1;
      
      ctx.beginPath();
      ctx.arc(x, y, radius, 0, 2 * Math.PI);
      ctx.fill();
    }
  }
}

registerPaint('seededRandomPattern', SeededRandomPattern);

CSS에서 적용하기

.seeded-random-background {
  --pattern-seed: 12345;
  --pattern-density: 150;
  --pattern-color: rgba(52, 152, 219, 0.6);
  background-image: paint(seededRandomPattern);
  background-color: white;
  min-height: 300px;
}

이 코드는 시드 값을 기반으로 일관된 랜덤 패턴을 생성합니다. 같은 시드 값을 사용하면 항상 동일한 패턴이 생성되므로, 새로고침해도 패턴이 변하지 않아요. 사용자별로 고유한 패턴을 만들 때 유용하게 활용할 수 있죠! 🎲

3. 이미지 데이터와 픽셀 조작

페인트 API에서는 ImageData를 활용해 픽셀 단위로 이미지를 조작할 수도 있어요. 이를 통해 복잡한 필터나 효과를 구현할 수 있습니다.

픽셀 노이즈 패턴

class PixelNoisePattern {
  static get inputProperties() {
    return [
      '--noise-scale',
      '--noise-color-1',
      '--noise-color-2'
    ];
  }

  paint(ctx, size, properties) {
    const scale = parseInt(properties.get('--noise-scale').toString()) || 4;
    const color1 = properties.get('--noise-color-1').toString() || '#3498db';
    const color2 = properties.get('--noise-color-2').toString() || '#e74c3c';
    
    const width = size.width;
    const height = size.height;
    
    // 픽셀 데이터 생성
    const imageData = ctx.createImageData(width, height);
    const data = imageData.data;
    
    // 픽셀별로 색상 결정
    for (let y = 0; y < height; y += scale) {
      for (let x = 0; x < width; x += scale) {
        // 랜덤하게 두 색상 중 하나 선택
        const useColor1 = Math.random() > 0.5;
        
        // 색상 파싱 (간단한 16진수 파싱)
        let r, g, b;
        if (useColor1) {
          r = parseInt(color1.slice(1, 3), 16);
          g = parseInt(color1.slice(3, 5), 16);
          b = parseInt(color1.slice(5, 7), 16);
        } else {
          r = parseInt(color2.slice(1, 3), 16);
          g = parseInt(color2.slice(3, 5), 16);
          b = parseInt(color2.slice(5, 7), 16);
        }
        
        // scale x scale 크기의 픽셀 블록 채우기
        for (let blockY = 0; blockY < scale && y + blockY < height; blockY++) {
          for (let blockX = 0; blockX < scale && x + blockX < width; blockX++) {
            const pixelIndex = ((y + blockY) * width + (x + blockX)) * 4;
            data[pixelIndex] = r;     // R
            data[pixelIndex + 1] = g; // G
            data[pixelIndex + 2] = b; // B
            data[pixelIndex + 3] = 255; // Alpha (불투명)
          }
        }
      }
    }
    
    // 이미지 데이터 그리기
    ctx.putImageData(imageData, 0, 0);
  }
}

registerPaint('pixelNoisePattern', PixelNoisePattern);

CSS에서 적용하기

.pixel-noise-background {
  --noise-scale: 4;
  --noise-color-1: #3498db;
  --noise-color-2: #e74c3c;
  background-image: paint(pixelNoisePattern);
  min-height: 300px;
}

이 코드는 두 가지 색상을 사용해 픽셀화된 노이즈 패턴을 생성합니다. 픽셀 단위로 이미지 데이터를 조작해 복잡한 효과를 만들 수 있어요. 레트로한 느낌의 디자인에 잘 어울리죠! 👾

리사주 곡선 패턴 시드 기반 랜덤 패턴 픽셀 노이즈 패턴 고급 패턴 기법 수학 함수, 시드 기반 랜덤, 픽셀 조작을 활용한 복잡한 패턴 생성 💡 Tip: Math.sin(), Math.cos() 같은 삼각함수와 시드 기반 랜덤 함수를 조합하면 더욱 복잡하고 아름다운 패턴을 만들 수 있습니다!

4. 애니메이션과 결합하기

CSS 애니메이션과 페인트 API를 결합하면 정말 멋진 동적 효과를 만들 수 있어요. CSS 변수를 애니메이션화하는 방법을 알아봅시다.

펄스 효과가 있는 원형 패턴

class PulsingCirclesPattern {
  static get inputProperties() {
    return [
      '--circle-color',
      '--circle-count',
      '--pulse-scale'
    ];
  }

  paint(ctx, size, properties) {
    const color = properties.get('--circle-color').toString() || '#3498db';
    const count = parseInt(properties.get('--circle-count').toString()) || 5;
    const pulseScale = parseFloat(properties.get('--pulse-scale').toString()) || 1.0;
    
    const width = size.width;
    const height = size.height;
    const centerX = width / 2;
    const centerY = height / 2;
    
    // 원 그리기
    for (let i = 0; i < count; i++) {
      const radius = (i + 1) * (Math.min(width, height) / (count * 2)) * pulseScale;
      
      ctx.strokeStyle = color;
      ctx.lineWidth = 2;
      ctx.beginPath();
      ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
      ctx.stroke();
    }
  }
}

registerPaint('pulsingCirclesPattern', PulsingCirclesPattern);

CSS에서 애니메이션 적용하기

.pulsing-circles {
  --circle-color: #3498db;
  --circle-count: 5;
  --pulse-scale: 1.0;
  background-image: paint(pulsingCirclesPattern);
  background-color: #f8f9fa;
  min-height: 300px;
  animation: pulse-animation 3s infinite alternate ease-in-out;
}

@keyframes pulse-animation {
  0% {
    --pulse-scale: 0.8;
    --circle-color: #3498db;
  }
  50% {
    --circle-color: #9b59b6;
  }
  100% {
    --pulse-scale: 1.2;
    --circle-color: #e74c3c;
  }
}

이 코드는 중심에서 퍼져나가는 원형 패턴을 만들고, CSS 애니메이션을 통해 원의 크기와 색상이 변하는 효과를 줍니다. CSS 애니메이션과 페인트 API의 조합으로 역동적인 배경을 만들 수 있어요! 💫

이런 고급 기법들을 활용하면 정말 독특하고 멋진 배경 패턴을 만들 수 있어요. 여러분의 창의력을 발휘해보세요! 이제 마지막으로 페인트 API의 미래와 전망에 대해 알아볼게요.

미래 전망과 결론 🔮 CSS 후디니의 가능성

CSS 후디니와 페인트 API는 웹 디자인의 미래를 보여주는 기술이에요. 이제 마무리로 이 기술의 미래 전망과 함께 오늘 배운 내용을 정리해볼게요! 🌈

CSS 후디니의 미래 전망

2025년 현재, CSS 후디니는 계속해서 발전하고 있어요. 앞으로 어떤 변화가 있을지 살펴볼까요?

  1. 브라우저 지원 확대: 2025년에는 대부분의 주요 브라우저에서 페인트 API를 지원하고 있지만, 앞으로는 더 많은 후디니 API(Layout API, Animation API 등)의 지원이 확대될 것으로 예상됩니다.

  2. 성능 최적화: 브라우저 벤더들은 후디니 API의 성능을 지속적으로 개선하고 있어요. 앞으로는 더 복잡한 그래픽도 부드럽게 처리할 수 있을 것입니다.

  3. 새로운 API 추가: 현재 개발 중인 Font Metrics API, Parser API 등이 추가되면 웹 개발자들은 더 많은 영역에서 브라우저 내부 기능에 접근할 수 있게 될 거예요.

  4. AI와의 결합: 2025년에는 AI 기술과 CSS 후디니의 결합이 시작되고 있어요. 사용자 행동이나 선호도에 따라 자동으로 최적화된 디자인을 생성하는 기술이 발전할 것으로 예상됩니다.

  5. 디자인 도구 통합: 디자인 툴(Figma, Adobe XD 등)에서 직접 CSS 후디니 코드를 생성하거나 미리보기할 수 있는 기능이 더욱 발전할 것입니다.

"CSS 후디니는 웹 플랫폼의 미래를 보여주는 창문입니다. 개발자들이 브라우저의 내부 동작에 접근할 수 있게 함으로써, 웹의 표현력과 성능을 획기적으로 향상시킬 것입니다."

- W3C CSS 워킹 그룹 -

2018 후디니 프로젝트 시작 2022 페인트 API 안정화 2025 주요 브라우저 지원 확대 2027 AI와 후디니 결합 2030 완전한 렌더링 제어 CSS 후디니의 미래 로드맵 Layout API 커스텀 레이아웃 알고리즘 Animation API 물리 기반 애니메이션 Font Metrics API 정밀한 텍스트 렌더링

배운 내용 정리

오늘 우리는 CSS 후디니 페인트 API에 대해 정말 많은 것을 배웠어요! 주요 내용을 다시 한번 정리해볼게요:

  1. CSS 후디니란? 브라우저의 렌더링 엔진에 직접 접근할 수 있게 해주는 API 모음으로, 웹 개발자에게 더 많은 창의적 자유를 제공합니다.

  2. 페인트 API의 기본 개념 자바스크립트로 CSS의 시각적 출력을 제어할 수 있게 해주는 API로, Canvas API와 유사한 방식으로 그래픽을 그릴 수 있습니다.

  3. 브라우저 지원 현황 2025년 현재 대부분의 주요 브라우저에서 페인트 API를 지원하고 있으며, 폴리필을 통해 하위 호환성도 확보할 수 있습니다.

  4. 기본 패턴 만들기 도트 패턴, 물결 패턴, 컨페티 패턴 등 다양한 배경 패턴을 만드는 방법을 배웠습니다.

  5. 실제 웹사이트 적용 방법 헤더, 섹션 구분선, 카드 등 다양한 웹 요소에 페인트 API를 적용하는 방법과 팁을 알아봤습니다.

  6. 고급 기법 수학 함수, 시드 기반 랜덤, 픽셀 조작, 애니메이션 등을 활용한 고급 패턴 생성 기법을 배웠습니다.

💡 실전 적용 팁

재능넷과 같은 플랫폼을 개발할 때 페인트 API를 활용하면 사용자별 맞춤형 배경이나 성취 배지 등을 구현할 수 있어요. 예를 들어, 사용자의 활동 데이터나 선호도를 기반으로 독특한 패턴을 생성해 개인화된 경험을 제공할 수 있습니다!

마무리 생각

CSS 후디니 페인트 API는 웹 디자인의 가능성을 크게 확장시켜주는 혁신적인 기술이에요. 이제 웹 개발자들은 더 이상 CSS의 한계에 좌절할 필요 없이, 상상하는 모든 디자인을 구현할 수 있게 되었습니다.

물론 아직은 초기 단계이고 브라우저 지원이 완벽하지 않지만, 웹의 미래는 분명 이런 방향으로 나아가고 있어요. 지금 페인트 API를 배우고 실험해보는 것은 미래를 준비하는 좋은 투자가 될 거예요! 🚀

여러분도 이 글에서 배운 내용을 바탕으로 나만의 독특한 배경 패턴을 만들어보세요. 재능넷 같은 플랫폼에서 여러분의 창의적인 디자인 스킬을 뽐내보는 것도 좋은 방법이 될 수 있어요! 🎨

CSS 후디니 페인트 API로 웹 디자인의 한계를 넘어서는 여정, 함께해서 즐거웠습니다! 다음에 또 다른 흥미로운 웹 기술로 만나요~ 👋

더 배우고 싶다면?

CSS 후디니에 대한 더 많은 정보와 예제는 MDN 웹 문서houdini.how 사이트에서 확인할 수 있어요!

또한 재능넷에서 웹 디자인과 개발에 관한 다양한 강의와 서비스를 찾아보세요. 여러분의 창의력을 발휘할 수 있는 기회가 기다리고 있습니다! 💪

후디니가 뭐길래? 🤔 CSS의 마법사를 소개합니다

CSS 후디니(Houdini)라는 이름 들어보셨나요? 마술사 해리 후디니처럼 CSS에 마법 같은 기능을 부여한다고 해서 붙여진 이름인데요, 진짜 웹 개발의 게임 체인저라고 할 수 있어요! ✨

간단히 말하자면, 후디니는 브라우저의 렌더링 엔진에 직접 접근할 수 있게 해주는 API 모음집이에요. 이전까지 개발자들은 CSS의 한계 내에서만 디자인을 구현해야 했지만, 후디니는 그 한계를 확 넓혀주는 마법 지팡이 같은 존재죠.

특히 오늘 집중적으로 알아볼 페인트 API(Paint API)는 후디니의 핵심 기능 중 하나로, 개발자가 직접 CSS 속성의 시각적 출력을 제어할 수 있게 해줍니다. 쉽게 말해서 "CSS로 그림 그리기"가 가능해진 거예요! 🎭

"CSS 후디니는 웹 개발자에게 슈퍼파워를 주는 것과 같습니다. 이제 CSS만으로도 상상하는 모든 디자인을 구현할 수 있어요."

- 어느 행복한 웹 개발자 -

CSS Paint API Layout API Animation API CSS 후디니: 브라우저 렌더링 엔진의 마법사 웹 디자인의 한계를 넘어서는 혁신적인 API 세트

후디니의 등장 배경을 간단히 살펴볼까요? 웹 개발자들은 오랫동안 CSS의 한계에 좌절해왔어요. "이것도 CSS로 할 수 있으면 얼마나 좋을까?" 하는 생각, 다들 한 번쯤 해보셨죠? 🤦‍♀️

그래서 구글을 중심으로 한 개발자 그룹이 "그럼 우리가 만들자!"라는 생각으로 후디니 프로젝트를 시작했어요. 2025년 현재, 후디니 API는 대부분의 모던 브라우저에서 지원되고 있으며, 특히 페인트 API는 크롬, 엣지, 파이어폭스 등 주요 브라우저에서 안정적으로 사용할 수 있게 되었답니다.

페인트 API의 기본 개념 💡 이해하기 쉽게 설명해드릴게요

자, 이제 본격적으로 페인트 API에 대해 알아볼까요? 페인트 API는 개발자가 CSS의 paint() 함수를 통해 자바스크립트로 그래픽을 그릴 수 있게 해주는 기능이에요. 캔버스 API와 비슷하다고 생각하시면 이해가 쉬울 거예요! 🖌️

페인트 API의 핵심 개념

  1. 페인트 워크렛(Paint Worklet): 자바스크립트로 작성된 그래픽 모듈로, CSS에서 호출할 수 있어요.

  2. paint() 함수: CSS 내에서 커스텀 페인트 워크렛을 호출하는 함수예요.

  3. registerPaint(): 새로운 페인트 워크렛을 등록하는 자바스크립트 메서드예요.

  4. paint() 메서드: 워크렛 내에서 실제 그래픽을 그리는 메서드로, Canvas API와 유사한 문법을 사용해요.

페인트 API를 사용하면 CSS 속성값으로 동적인 그래픽을 생성할 수 있어요. 예를 들어, background-image: paint(myPattern);처럼 사용하면 'myPattern'이라는 이름의 페인트 워크렛이 배경 이미지를 그려줍니다.

이게 왜 혁신적이냐고요? 기존에는 복잡한 패턴을 만들려면 이미지 파일을 사용하거나 복잡한 CSS 트릭을 써야 했어요. 하지만 페인트 API를 사용하면:

  1. 동적으로 변하는 패턴을 만들 수 있어요 (사용자 입력이나 시간에 따라 변화 가능)

  2. 추가 이미지 파일 없이 가벼운 코드만으로 복잡한 그래픽 구현 가능

  3. CSS 변수와 연동해 쉽게 커스터마이징 가능

  4. 브라우저 렌더링 엔진 레벨에서 최적화되어 성능이 좋음

간단한 예시를 통해 페인트 API의 기본 구조를 살펴볼게요:

1. 페인트 워크렛 정의하기 (JavaScript)

// myPattern.js
class MyPattern {
  paint(ctx, size, properties) {
    // Canvas API와 유사한 그리기 코드
    ctx.fillStyle = 'purple';
    ctx.fillRect(0, 0, size.width, size.height);
    
    // 원 그리기
    ctx.fillStyle = 'gold';
    ctx.beginPath();
    ctx.arc(size.width/2, size.height/2, 50, 0, 2 * Math.PI);
    ctx.fill();
  }
}

// 워크렛 등록
registerPaint('myPattern', MyPattern);

2. 워크렛 로드하기 (JavaScript)

// 메인 JavaScript 파일에서
if ('paintWorklet' in CSS) {
  CSS.paintWorklet.addModule('myPattern.js');
}

3. CSS에서 사용하기

.my-element {
  background-image: paint(myPattern);
  width: 200px;
  height: 200px;
}

위 코드를 실행하면 보라색 배경에 금색 원이 그려진 요소가 생성됩니다. 꽤 간단하죠? 이게 페인트 API의 기본 사용법이에요! 😄

class MyPattern { paint(ctx, size, props) { ctx.fillStyle = 'purple'; ctx.fillRect(0, 0, size.width, size.height); ctx.fillStyle = 'gold'; ctx.beginPath(); ctx.arc(size.width/2, size.height/2, 50, 0, 2*Math.PI); ctx.fill(); } } 실행 결과 페인트 워크렛 코드 .my-element { background-image: paint(myPattern); }

페인트 API의 진짜 매력은 CSS 변수(Custom Properties)와 함께 사용할 때 빛을 발해요. CSS 변수를 통해 JavaScript 없이도 페인트 워크렛의 동작을 제어할 수 있거든요! 이건 나중에 더 자세히 알아볼게요. 일단 기본 개념은 이해되셨죠? 🙌

2025년 브라우저 지원 현황 🌐 어디서 쓸 수 있을까?

페인트 API를 실제 프로젝트에 적용하기 전에 브라우저 지원 현황을 확인해볼까요? 2025년 3월 현재 상황을 정리해봤어요!

CSS 페인트 API 브라우저 지원 현황 (2025년 3월 기준)

  1. Chrome: 완전 지원 (버전 65부터)

  2. Edge: 완전 지원 (Chromium 기반 전환 이후)

  3. Firefox: 완전 지원 (2024년 말부터)

  4. Safari: 부분 지원 (최신 버전에서 flag 활성화 필요)

  5. Opera: 완전 지원 (Chromium 기반)

  6. Samsung Internet: 완전 지원

  7. 모바일 브라우저: Android Chrome, iOS Safari 최신 버전에서 지원

와우! 2025년에는 대부분의 주요 브라우저에서 페인트 API를 사용할 수 있게 되었네요. 2023년까지만 해도 Firefox와 Safari에서 지원이 제한적이었는데, 이제는 거의 모든 브라우저에서 사용 가능해졌어요. 특히 Firefox가 2024년 말부터 완전 지원을 시작한 건 웹 개발자들에게 정말 반가운 소식이죠! 🎉

하지만 아직 Safari에서는 약간의 제한이 있으니, 폴리필(polyfill)이나 대체 방안을 준비해두는 것이 좋아요. 다행히 CSS의 @supports 규칙을 사용하면 페인트 API를 지원하지 않는 브라우저에 대한 대체 스타일을 쉽게 제공할 수 있답니다.

/* 페인트 API 지원 여부 확인 */
@supports (background: paint(id)) {
  .my-element {
    background-image: paint(myPattern);
  }
}

/* 페인트 API를 지원하지 않는 브라우저용 대체 스타일 */
@supports not (background: paint(id)) {
  .my-element {
    background-image: linear-gradient(purple, darkpurple);
  }
}

이렇게 하면 페인트 API를 지원하지 않는 브라우저에서도 사용자 경험을 해치지 않고 적절한 대체 디자인을 제공할 수 있어요. 똑똑하죠? 😏

CSS 페인트 API 브라우저 지원 현황 (2025) Chrome 100% Edge 100% Firefox 95% Safari 70% Opera 100% 완전 지원 부분 지원 미지원

재능넷 같은 웹 플랫폼을 개발할 때도 이런 브라우저 호환성을 고려하는 게 중요해요. 사용자들이 어떤 브라우저를 사용하든 일관된 경험을 제공할 수 있으니까요! 🌈

이제 기본 개념과 브라우저 지원 현황을 알았으니, 실제로 멋진 배경 패턴을 만드는 방법을 알아볼까요?


- 지식인의 숲 - 지적 재산권 보호 고지

지적 재산권 보호 고지

  1. 저작권 및 소유권: 본 컨텐츠는 재능넷의 독점 AI 기술로 생성되었으며, 대한민국 저작권법 및 국제 저작권 협약에 의해 보호됩니다.
  2. AI 생성 컨텐츠의 법적 지위: 본 AI 생성 컨텐츠는 재능넷의 지적 창작물로 인정되며, 관련 법규에 따라 저작권 보호를 받습니다.
  3. 사용 제한: 재능넷의 명시적 서면 동의 없이 본 컨텐츠를 복제, 수정, 배포, 또는 상업적으로 활용하는 행위는 엄격히 금지됩니다.
  4. 데이터 수집 금지: 본 컨텐츠에 대한 무단 스크래핑, 크롤링, 및 자동화된 데이터 수집은 법적 제재의 대상이 됩니다.
  5. AI 학습 제한: 재능넷의 AI 생성 컨텐츠를 타 AI 모델 학습에 무단 사용하는 행위는 금지되며, 이는 지적 재산권 침해로 간주됩니다.

재능넷은 최신 AI 기술과 법률에 기반하여 자사의 지적 재산권을 적극적으로 보호하며,
무단 사용 및 침해 행위에 대해 법적 대응을 할 권리를 보유합니다.

댓글 작성
0/2000

댓글 0개