인터랙션

긁어서 공개하는 캔버스 스크래치 카드

복권처럼 표면을 긁으면 상품이 드러나고, 일정 비율을 넘으면 자동 공개.

Canvas 2DglobalCompositeOperationPointer EventsgetImageDataDPR
라이브 데모
새 탭에서 열기
데모 불러오는 중…

제작 과정

한 줄 요약

캔버스에 회색 표면을 칠해 상품을 덮고, Pointer로 긁은 자리를 destination-out 합성으로 지웁니다. 픽셀 알파를 샘플링해 긁힌 비율을 계산하고 임계값(60%)을 넘으면 전체를 자동 공개합니다.

이럴 때 필요해요

이벤트쿠폰복권 같은 "긁어서 확인" 인터랙션으로 참여를 유도할 때. 캔버스만으로 라이브러리 없이 구현됩니다.

어떻게 동작하나

  1. 표면을 그라데이션으로 칠하고 안내 문구를 올립니다.

  2. onPointerMove에서 globalCompositeOperation="destination-out"으로 원을 그려 지움.

  3. getImageData로 알파 0 픽셀 비율을 샘플링 임계값 넘으면 표면을 페이드아웃.

놓치기 쉬운 것

  • DPR 보정을 안 하면 고해상도 화면에서 긁힌 자국이 흐릿함.

  • 매 프레임 전체 getImageData는 무거움 떼는 순간이나 N픽셀 간격 샘플링으로 비용 절감.

  • touch-none + setPointerCapture로 모바일 스크롤이탈을 막아야 자연스러움.

이런 곳에 써요

  • 프로모션 쿠폰룰렛 이벤트

  • 온보딩의 깜짝 보상 공개

소스 코드

· 데모 페이지에서 자동 추출
import type { Metadata } from "next";
import { ScratchCardDemo } from "./-components/ScratchCardDemo";

export const metadata: Metadata = {
  title: "스크래치 카드 (데모)",
  description:
    "복권처럼 표면을 긁어 상품을 공개하는 캔버스 스크래치 카드. Pointer로 긁은 자리를 destination-out 합성으로 지우고, 픽셀 샘플링으로 긁힌 비율을 계산해 임계값에서 자동 공개. 브러시 크기·리셋.",
  robots: { index: false, follow: false },
};

export default function Page() {
  return (
    <main className="flex min-h-[100dvh] items-center justify-center bg-gradient-to-br from-slate-50 via-white to-amber-50/40">
      <ScratchCardDemo />
    </main>
  );
}
20조회수

댓글