Community이미지github.com

habom2310/swarm-build

웹사이트에 swarm-build 애니메이션을 추가합니다. 이름과 색상이 있는 커서 떼가 영역별로 박스를 그리고 스크린샷을 점진적으로 구성하거나, 라이브 페이지 전체를 블록 단위로 재구축합니다. 마치 멀티플레이어 디자인 파일처럼 동작합니다.

swarm-build란 무엇인가요?

swarm-build는 의존성이 없는 ES 모듈로, 웹 페이지에 협업형 커서 애니메이션을 구현합니다. Image 모드에서는 이미지 영역을 커서가 드래그하며 박스를 그리고, Page 모드에서는 실제 DOM 요소를 순서대로 재구성합니다. React, Next.js, Vue, Svelte, Astro 등 모든 프레임워크와 함께 사용할 수 있으며, 마크다운과 CSS로 간단히 설정할 수 있습니다. 에이전트 이름과 색상을 사용자 정의할 수 있고, 접근성을 고려하여 reduced motion 설정 시 애니메이션이 비활성화됩니다. 이 라이브러리는 CSP(Content Security Policy)와 Trusted Types 환경에서도 안전하게 동작합니다.

지원 대상~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/habom2310/swarm-build/tree/HEAD/skills/swarm-build

Installed? Explore more 이미지 skills: steipete/songsee, affaan-m/frontend-design, mattpocock/improve-codebase-architecture · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

미리보기

스킬 README에서

swarm-build preview

문서

swarm-build은(는) 무엇을 하나요?

swarm-build는 의존성이 없는 하나의 ES 모듈(src/swarm-build.js, 약 600줄)과 선택적 CSS 파일(src/swarm-build.css)로 구성됩니다. 두 가지 모드가 있습니다:

  • Image 모드, swarmBuild(img): 빈 캔버스가 <img>(또는 CSS background-image가 있는 요소)를 덮고, 각 영역이 커서가 W × H 배지를 가진 박스를 드래그한 후 나타납니다.
  • Page 모드, swarmBuildPage("[data-swarm-block]"): 라이브 페이지의 표시된 요소들이 사라졌다가 커서가 하나씩 재구축합니다. 일반 텍스트 블록(제목, 짧은 문단)은 스스로 타이핑됩니다. 다른 블록 안에 있는 블록은 부모가 완료될 때까지 기다립니다. 화면 아래에 있는 블록은 스크롤되어 보일 때까지 기다리므로, swarm이 사용자를 따라 페이지 아래로 이동합니다.

두 모드 모두 커서는 마지막에 사라지고 라이브러리가 만든 모든 변경사항은 원래대로 복구됩니다.

1. 설치

src/swarm-build.js, src/swarm-build.d.ts, src/swarm-build.css 파일을 이 저장소에서 프로젝트로 복사한 후(예: lib/swarm-build/) 상대 경로로 임포트합니다. 의존성이 없고 빌드 단계도 필요하지 않습니다.

npm view swarm-build가 패키지가 게시되었다고 표시하는 경우에만: npm install swarm-build로 설치한 후 import { swarmBuild } from "swarm-build"와 import "swarm-build/style.css"로 임포트합니다.

2a. Page 모드: 블록 표시하기

  1. 페이지의 마크업을 읽고 디자이너가 그릴 블록을 선택합니다: 내비게이션 바, 히어로 제목, 히어로 문단, 각 버튼, 각 카드, 차트, 표, 푸터. 일반적인 랜딩 페이지는 25~60개 정도입니다.
  2. 각 블록에 data-swarm-block을 추가합니다.
    • 컨테이너(카드)와 그 안의 텍스트(제목, 문단)를 표시하면 "프레임 먼저, 그 다음 내용 채우기"가 작동합니다.
    • 내용이 일반 텍스트인 제목과 짧은 문단은 타이핑됩니다. 인라인 마크업(링크, <b>)이 있는 요소는 대신 스윕(sweep)됩니다.
    • 레이아웃만 담당하는 래퍼(그리드, 자체 배경이 없는 섹션)는 건너뜁니다. 그런 요소를 숨기면 내부의 모든 것이 한꺼번에 숨겨집니다.
  3. 방문자가 즉시 필요로 하는 고정 또는 스티키 UI(예: 쿠키 배너, 채팅 위젯)는 표시하지 마세요.
  4. 콘텐츠가 DOM에 로드된 후에 호출합니다:
import { swarmBuildPage } from "./lib/swarm-build/swarm-build.js";
swarmBuildPage("[data-swarm-block]", { speed: 1.5 });

스크립트 실행 전에 블록을 숨기려면(완성된 페이지가 번쩍 나타나는 것을 방지) 각 블록에 data-swarm-pending 속성을 추가하고 CSS 파일을 포함하세요.

2b. Image 모드: 영역 선택하기

영역은 무엇이 어떤 순서로 빌드될지 결정합니다. 좋은 영역은 애니메이션이 의도적으로 보이게 만드므로, 이 단계를 건너뛰지 마세요.

  1. 이미지를 열고 살펴봅니다(이미지 파일을 읽거나 페이지 스크린샷을 찍습니다).
  2. 디자이너가 그릴 6~15개의 의미 있는 블록을 나열합니다: 내비게이션 레일, 헤더, 검색 바, 카드, 차트, 목록, 푸터.
  3. 각 블록을 이미지 너비와 높이의 백분율(0~100)로 x y w h 형식으로 작성합니다. 픽셀 크기로 측정: x = left / imageWidth * 100.
  4. 사람이 화면을 구성하는 순서대로 정렬합니다: 크롬 먼저(레일, 헤더), 그 다음 콘텐츠는 위에서 아래로.
  5. 작은 간격은 남겨둡니다. 영역이 덮지 않는 부분은 마지막에 캔버스가 사라질 때 나타나므로, 모든 픽셀을 덮을 필요는 없습니다.

영역을 이미지에 data-swarm-regions="0 0 18 100, 21 3.5 47 5.5, ..."로 추가하거나, JavaScript에서 regions: [{ x, y, w, h }]로 전달합니다. 영역 없이 사용하면 라이브러리는 일반적인 사이드바, 헤더, 카드 레이아웃을 사용하며, 이는 이미지와 거의 일치하지 않습니다.

3. 연결하기

일반 HTML:

<link rel="stylesheet" href="/lib/swarm-build/swarm-build.css" />
<img src="/shot.png" alt="..." width="1200" height="800"
     data-swarm-pending
     data-swarm-regions="0 0 18 100, 21 3.5 47 5.5, 21 13 24 16" />
<script type="module">
  import { swarmBuild } from "/lib/swarm-build/swarm-build.js";
  swarmBuild(document.querySelector("img[data-swarm-regions]"));
</script>

React 또는 Next.js (클라이언트 컴포넌트):

"use client";
import { useEffect, useRef } from "react";
import { swarmBuild } from "@/lib/swarm-build/swarm-build.js";

export function BuiltImage(props: React.ComponentProps<"img"> & { regions: string }) {
  const ref = useRef<HTMLImageElement>(null);
  useEffect(() => {
    const swarm = swarmBuild(ref.current!);
    return () => swarm.destroy();
  }, []);
  const { regions, ...img } = props;
  return <img ref={ref} {...img} data-swarm-pending="" data-swarm-regions={regions} />;
}

Vue, Svelte 또는 Astro의 경우에도 동일하게 마운트 후 swarmBuild(el)을 호출하고 언마운트 시 destroy()를 호출합니다. 여러 이미지(예: iPad와 휴대폰)가 하나의 swarm을 공유할 수 있습니다: swarmBuild([ipadImg, phoneImg]).

4. 옵션

옵션기본값설명
regions (대상별)data-swarm-regions, 그 다음 일반빌드할 영역, 순서대로
agents내장된 6개의 이름과 색상[{ name, color, text }], 사이트의 팔레트와 방문자에 맞춤
speed12는 지속 시간을 절반으로 줄입니다(1에서 1015개 영역 기준 약 68초)
start"visible""now"는 이미지가 스크롤되어 보일 때까지 기다리지 않고 즉시 시작
canvas"#fff"빌드되지 않은 캔버스의 색상; 스크린샷 배경과 일치시킴
zIndex2147483000고정 커서 레이어의 스택 순서; 모달이나 헤더가 위에 있어야 하면 낮춤
onDone없음빌드가 완료되거나 finish()가 호출되면 한 번 호출
typeSpeed (Page 모드)1타이핑 속도; 2는 두 배 빠름

반환값에는 finished, finish(), destroy()가 있습니다:

  • finished는 항상 resolve되는 Promise로, swarm이 어떻게 끝나든 resolve됩니다.
  • finish()는 완성된 이미지로 바로 이동하며 onDone이 실행됩니다.
  • destroy()는 모든 것을 즉시 제거하며 onDone은 실행되지 않습니다. 언마운트 시 호출합니다.
  • setSpeed(n)은 실행 중에 속도를 변경합니다.

Page 모드에서 start의 기본값은 "now"이고, Image 모드에서는 "visible"입니다.

5. 지켜야 할 규칙

  • data-swarm-pending과 CSS 파일은 스크립트가 시작될 때까지 이미지를 숨겨서 완성된 상태가 먼저 나타나는 것을 방지합니다. 스크립트가 실행되지 않으면 CSS는 4초 후에 이미지를 표시합니다. 이미지가 페이지의 LCP 요소이고 로드 시간이 효과보다 중요한 경우 속성을 제거하세요.
  • 접근성 설정 감소(prefers-reduced-motion: reduce)에서는 완성된 이미지가 표시되고 애니메이션이 실행되지 않습니다. 이를 재정의하지 마세요.
  • 커서는 페이지 위의 고정된 전체 뷰포트 레이어에 위치합니다(pointer-events: none).
  • 실행 중에 라이브러리는 이미지 바로 뒤, 이미지의 부모 안에 오버레이를 삽입합니다. 부모가 static이었다면 position: relative도 설정됩니다. 두 가지 모두 마지막에 원래대로 복구됩니다.
    • 이미지에 자체 블록 레벨 부모(<div> 또는 <figure>)를 제공하세요. 인라인 부모(<a> 또는 <picture>)는 오버레이 위치가 잘못될 수 있습니다.
    • :last-child 또는 Tailwind space-y-*와 같은 형제 CSS는 오버레이가 있는 동안 잠시 변경될 수 있습니다.
  • 이미지는 이미지의 내용 박스에 맞게 늘어난 CSS 배경으로 복사됩니다. 이미지의 테두리와 패딩은 문제없지만, object-fit: cover 또는 contain 크롭은 재현되지 않습니다.
  • 엄격한 CSP 또는 Trusted Types 환경에서도 변경이 필요하지 않습니다: 라이브러리는 모든 요소를 DOM 호출로 구성하고 CSSOM을 통해 스타일을 설정하며, innerHTML, <style> 또는 인라인 스크립트를 사용하지 않습니다. 이미지 URL은 img-src에서 허용되어야 합니다.

6. 확인

  1. 페이지를 로드하고 전체 빌드 과정을 한 번 시청하세요. 각 박스는 이미지의 실제 UI 블록 위에 위치해야 하며, 빈 공간이나 두 블록에 걸쳐 있지 않아야 합니다.
  2. 휴대폰 너비(375px)에서 확인하세요. 배지와 이름 태그는 고정 크기이므로 매우 작은 이미지에서는 비좁게 느껴질 수 있습니다. 그런 경우 더 적고 더 큰 영역을 사용하세요.
  3. 운영 체제 또는 브라우저 개발자 도구에서 접근성 설정 감소를 켜세요: 이미지가 즉시 나타나야 하며 커서가 없어야 합니다.
  4. 콘솔에 오류가 없는지, 완료 후 DOM에 aria-hidden swarm 요소가 남아 있지 않은지 확인하세요.

관련 스킬