Communitygithub.com

ishmum123/kinetic-promo-video

설명만으로 HTML과 코드 기반 모션으로 제작하는 브로드캐스트 수직 프로모션 비디오. 편집기, 스톡 영상, 타임라인 앱 없이 타임스탬프로 모든 프레임 재현 가능.

kinetic-promo-video란 무엇인가요?

이 스킬은 비즈니스에 대한 간단한 설명만으로 전문적인 수직 프로모션 비디오(1080×1920, 30fps, H.264)를 생성합니다. HTML, CSS, JavaScript로 구동되며, 하나의 HTML 페이지를 프레임별로 렌더링하고 인코딩하여 `promo.mp4`를 만듭니다. 사용자는 브리프(설명), 레퍼런스(선택 사항), 브랜드 정보, 오디오 유형(내레이션 또는 무음)만 제공하면 됩니다. 스킬은 자동으로 비트 시트(타임라인)를 작성하고, 음성 해설을 생성하며, 각 장면을 제작합니다. Claude Code, Cursor, Codex 등에서 실행되며, 모든 프레임이 동일한 타임스탬프로 재현 가능하도록 결정론적 설계를 따릅니다. 완성된 결과물은 `promo.mp4`, `scene.html`, `render.py`, `voice.srt`, README를 포함하며, 사용자는 몇 번의 명령어로 전체 워크플로우를 실행할 수 있습니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add ishmum123/kinetic-promo-video

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

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

문서

Kinetic Promo Video

비즈니스 설명만으로 브로드캐스트 스타일의 수직 프로모션 비디오를 만듭니다. 비디오는 일시 정지된 마스터 클록으로 구동되는 단일 HTML 페이지로 제작되며, 프레임별로 렌더링되고 인코딩됩니다. 편집기, 스톡 영상, 타임라인 앱이 필요 없으며, 모든 프레임은 타임스탬프에서 재현 가능합니다.

입력

  • $brief — 대상(제품/서비스)이 무엇인지, 누구를 위한 것인지, 차별점이 무엇인지. 필수. 대화, 리포지토리 README에서 가져오거나 질문하세요.
  • $reference — 선택 사항. 일치시킬 비주얼의 동영상 URL 또는 로컬 파일.
  • $brand — 선택 사항. 이름, 태그라인, URL, 색상, 로고. 없으면 명확히 표시된 플레이스홀더를 사용하세요(절대 브랜드를 임의로 생성하여 최종 결과물로 제시하지 마십시오).
  • $duration — 선택 사항. 기본값 3035초(무음), 4560초(내레이션)(음성이 길이를 결정 — references/audio.md 참조). Shorts/Reels/TikTok의 경우 60초 미만 유지.
  • $audio — 기본값: 내레이션, 음악 없음. 사용자가 무음 작품을 요청하지 않는 한 음성 해설을 작성하고 타임라인을 구성하세요. 음악은 명시적으로 요청되지 않는 한 항상 꺼져 있어야 합니다.

목표

promo.mp4 — 1080×1920, 30fps, H.264, 첫 시청에 재생 가능하고 정확함 — 여기에 이를 생성한 scene.html, 이를 재현하는 render.py, 내레이션 작품용 voice.srt 자막 파일, 비트 시트와 리브랜딩 상수가 포함된 README가 포함됩니다. 성공은 "파일이 존재함"이 아닙니다: 직접 확인한 프레임이 깔끔하게 읽히고, 텍스트가 겹치지 않으며, 큐 이전에 요소가 보이지 않고, 침묵 구간이 없어야 합니다.

단계

1. 도구 체인 확인

which ffmpeg ffprobe yt-dlp python3
python3 -m venv .venv && .venv/bin/pip install -q playwright && .venv/bin/playwright install chromium

ffmpeg와 Playwright용 Chromium은 필수 요구 사항입니다. yt-dlp는 레퍼런스 분석에만 필요합니다. venv 사용을 권장합니다 — 사용자의 시스템 Python은 외부 관리형일 수 있습니다.

성공 기준: ffmpeg -version이 작동하고 .venv/bin/python -c "from playwright.sync_api import sync_playwright; sync_playwright().start().chromium.executable_path"가 경로를 출력합니다.

2. 시각적 목표 설정

두 가지 경로 — $reference 존재 여부에 따라 선택.

2a. 레퍼런스 제공 → 분석

references/teardown.md를 읽고 따르세요. 간단히: 다운로드, 프로브, 1fps 접촉 시트 추출, 시트 이미지를 실제로 읽고, 코드를 작성하기 전에 치수, 지속 시간, 팔레트, 타이포그래피 처리, 비트 구조, 모션 어휘를 기록하세요.

프레임별로 확인하지 않은 레퍼런스를 설명하지 마십시오. 페이지 제목이나 설명은 모션 디자인에 대해 아무것도 알려주지 않습니다.

2b. 레퍼런스 없음 → 먼저 대상 자체의 언어 도출

default-style.md를 아직 열지 마세요. 실제 대상에 대한 네 가지 질문에 답하는 데 2분을 투자하세요:

  1. 대상은 무엇인가요? 책, 항아리, 송장, 얼굴, 대시보드. 이것들이 움직여야 하는 것들입니다.
  2. 어떤 빛 속에 있나요? 독서등, 쇼룸, 달빛, 화면 빛, 창문을 통한 햇빛.
  3. 물리적으로 어떻게 움직이나요? 질량이 있는 것은 안정됩니다. 종이는 접히고 구겨집니다. 액체는 퍼집니다. 데이터는 스냅됩니다.
  4. 척추는 무엇인가요? 주장을 전달하는 반복되는 요소 — 카운트다운, 밤을 가로지르는 시계, 길어지는 영수증, 채워지는 경로. 이상적으로는 장식이 아닌 주장 자체여야 합니다.

네 가지 답변이 일관된 느낌을 주면 그것을 구축하세요. 밤샘 수리에 관한 스킨케어 프로모션은 나이트 팔레트, 세리프체, 느린 안정화 모션, 오후 10시→오전 7시 다이얼을 사용합니다 — 빛나는 고리가 아닙니다.

대상이 구체적인 것을 암시하지 않을 때(대부분의 B2B 소프트웨어, 추상 서비스) 하우스 스타일로 대체하세요. 그런 다음 references/default-style.md를 읽고 그대로 사용하세요: 완전하고 검증된 사양입니다(다크 네이비 + 파란 빛, 기하학적 산세리프, 블러 인 운동 타이포, 빛나는 지평선, 링 아웃트로). 사용자에게 어떤 스타일을 사용 중인지 한 줄로 알리고 레퍼런스 비디오를 지정하여 변경할 수 있다고 말한 다음 계속 진행하세요. 승인을 위해 멈추지 마십시오.

구축 전 정직성 확인. 비트 타이밍이 템플릿의 약 0.5초 이내이고 시그니처 샷(에코 단어 스택, 링 블룸, 지평선 플러스 슬래브 카드, 텍스트 이동의 유일한 방법인 블러 인)이 유지된다면 템플릿을 대상에 맞게 디자인한 것이 아니라 리스킨한 것입니다. 의도적으로 대체를 선택한 경우에는 괜찮지만, 그렇지 않은 경우에는 결함입니다.

성공 기준: 구축하는 동안 참조할 수 있는 짧은 서면 사양(캔버스 크기, fps, 지속 시간, 팔레트 16진수, 글꼴, 사용할 모션 동작). 대상 고유 언어를 도출한 경우 척추와 사용하지 않기로 선택한 동작도 명시합니다.

3. 비트 시트 작성

references/audio.md를 읽고 음성 트랙을 먼저 작성하세요 — 기본적으로 켜져 있습니다. 음성이 타임라인을 제어합니다: 대사를 생성하고, 측정하고, 둥근 숫자에 맞추기보다는 측정값에서 비트 시간을 도출하세요. 측정된 대사별 타이밍을 유지하세요 — 이는 전달 시 voice.srt가 됩니다. 사용자가 무음 작품을 요청한 경우에만 이 단계를 건너뛰세요.

references/beats.md에서 구조와 복사 규칙을 읽은 다음 사용자의 실제 차별점을 비트에 매핑하세요. 중간 부분이 제품이 판매되는 곳입니다: 형용사가 아닌 이 제품이 더 나은 구체적인 이유가 포함되어야 합니다. 음소거 재생을 가정하세요 — 대부분의 Shorts/Reels 시청자는 음성을 듣지 않습니다 — 따라서 음성 해설의 모든 주장은 내레이션뿐만 아니라 화면 텍스트로도 나타나야 합니다.

장면을 구축하기 전에 비트 시트를 표(시간 범위 → 비트)로 작성하세요. 페이싱을 잘못 잡으면 장면이 구축된 후 수정하는 데 훨씬 더 많은 비용이 듭니다.

산출물: $duration에 합산되는 명시적인 초 범위가 있는 비트 표.

성공 기준: 모든 비트가 제품에 대한 실제 내용으로 추적되며, 범위가 연속적이고 0.3초 이상의 간격이 없습니다.

4. 템플릿에서 스캐폴딩

$SKILL는 이 SKILL.md를 보유한 이 스킬의 디렉토리입니다. 경로를 추측하지 말고 스킬 목록에서 확인하세요. 종종 읽기 전용으로 마운트되지만 모든 것이 복사되므로 괜찮습니다.

mkdir -p video && cp "$SKILL/templates/render.py" video/
cp "$SKILL/templates/scene-starter.html" video/scene.html
bash "$SKILL/templates/fetch-fonts.sh" video/fonts     # Poppins 서브셋, ~40KB

scene-starter.html에는 이미 애니메이션 하니스(seek, win, io, pop, swap, draw, 시드된 RNG, 분위기)와 복사할 가치가 있는 모든 패턴을 다루는 7개의 예시 비트가 포함되어 있습니다. 하니스를 다시 작성하지 마십시오 — 규칙에 나열된 버그를 인코딩합니다. 예시 비트를 교체하고 그 위의 모든 것은 유지하세요.

성공 기준: python render.py --contact가 건드리지 않은 스타터에서 contact.png를 생성합니다.

5. 장면 구축

비트당 하나의 IIFE, 각각 win(layer, tIn, tOut)으로 게이트된 자체 layer()를 생성합니다. 내부에서 애니메이션되는 모든 요소는 정확히 하나의 io() / pop() / swap() 호출을 가져야 합니다.

UI 모형(대시보드, 전화기, 노트북, 카드, 칩)을 일반 DOM + CSS로 구축하고 애니메이션으로 넣으세요 — 순수한 타입으로는 불가능한 "실제 제품" 느낌을 전달합니다. 차트는 div와 인라인 SVG입니다. 차트 라이브러리, 이미지, 외부 요청이 없습니다.

하드 컷은 합법적인 움직임입니다: 정확한 시간 경계를 공유하는 두 개의 win() 레이어, steps(1,end)로 진입하면 의도적인 단일 프레임 컷이 생성됩니다 — 스토리 월드 → 평평한 브랜드 색상과 같은 톤 변화에 적합합니다. 다른 모든 것은 이징됩니다. 컷이 유일한 컷이기 때문에 효과적입니다.

실제 다색 로고는 어두운 장면과 평평한 브랜드 배경 모두에서 종종 읽기 어렵습니다 — 색상을 변경하는 대신 작은 흰색 판에 자산을 배치하세요.

규칙: 규칙 섹션을 참조하세요. 스타일 선호도가 아닙니다 — 각각은 이 스킬이 이미 경험한 특정 실패입니다.

성공 기준: python render.py --contact가 오류 없이 렌더링됩니다.

6. 미리보기 루프 — 모든 프레임 확인

python render.py --contact          # 24프레임 개요, ~20초
python render.py --at 6.2 12.0 19.5 # 특정 순간, 전체 해상도

결과 PNG를 이미지 읽기 도구(하니스가 호출하는 모든 것)로 읽고 검사하세요. 그런 다음 수정하고 반복하세요. 시트가 깨끗해질 때까지 여기서 반복하세요 — 전체 렌더링은 10배 느리므로 피드백 루프로 사용하지 마십시오.

두 보기는 다른 질문에 답합니다. 접촉 시트는 구조(타이밍, 겹침, 데드 프레임, 비트 순서)를 위한 것입니다. 프레임당 270×480이며 어둡거나 대비가 낮은 작업을 체계적으로 덜 읽습니다 — 시트에서 흐릿하고 깨진 것처럼 보이는 조각이 전체 크기에서는 종종 깨끗합니다. 대비, 팔레트 및 가독성은 --at 프레임에서만 판단하고, 팔레트가 어두울 때마다 비트당 하나 이상, 픽토그램 또는 일러스트레이션당 하나 이상을 가져오세요 — 타일 크기에서 인식 가능성을 판단할 수 없습니다(규칙 12 참조). 시트가 과장한 것을 수정하기 위해 밝기를 높이지 마십시오.

각 패스에서 찾아야 할 것:

  • 전환 중 동시에 읽을 수 있는 두 개의 텍스트 조각
  • 큐 전에 보이는 모든 것(고전적인 fill: 'both' 버그 — 규칙 참조)
  • 분위기 대신 인식 가능한 모양으로 읽히는 배경 요소
  • 겹친 반투명 블롭 — 겹친 알파 레이어는 보이는 교차 아크로 합성되어 디스크로 읽힙니다. 프레임보다 큰 자체 상자 내부에서 용해되는 림이 있는 하나의 요소를 사용하세요.
  • 데드 프레임 — 화면에 아무것도 없는 순간
  • 프레임 가장자리에 밀집되거나 전화 화면에 비해 너무 작은 텍스트 또는 모형

인적 확인: 필수는 아니지만, 사용자가 있는 경우 전체 렌더링 전에 접촉 시트를 보여주세요 — 페이싱 및 복사 노트는 지금이 가장 저렴합니다.

성공 기준: 모든 프레임이 깔끔하게 읽히고 위의 결함이 없는 접촉 시트를 확인했습니다.

7. 렌더링 및 확인

먼저 인코더를 스모크 테스트하세요. ~2초 슬라이스를 렌더링하고(복사본 render.py에 범위 플래그가 있으면 사용하고, 그렇지 않으면 지속 시간 상수를 일시적으로 줄여서) ffprobe로 결과를 확인하세요. 인코더 및 먹스 문제는 다중 분 전체 렌더링 후가 아니라 여기서 몇 초 안에 표면화됩니다.

python render.py                    # -> promo.mp4, 프레임당 약 1개의 스크린샷
# 내레이션 작품: 인코더 프로세스가 종료된 후에만 먹스
ffmpeg -y -i promo.mp4 -i vo/voice.wav -c:v copy -c:a aac -b:a 192k promo_av.mp4
ffprobe -v error -show_entries format=duration \
        -show_entries stream=codec_type,codec_name,width,height,nb_frames \
        -of default=noprint_wrappers=1 promo_av.mp4
ffmpeg -y -v error -i promo_av.mp4 -vf "fps=1/1.2,scale=180:320,tile=10x3" -frames:v 1 verify.png

전체 렌더링을 백그라운드에서 실행하세요. 프레임당 약 1개의 스크린샷입니다 — 50초 비디오는 ~1500 프레임이며 600초 명령 시간 초과를 편안하게 초과합니다. 렌더링 프로세스가 종료될 때까지 폴링하고 mp4가 나타날 때까지 기다리지 마세요: 파일이 완성되기 훨씬 전에 디스크에 존재하며, 조기에 먹스하면 moov atom not found가 발생합니다.

내레이션 작품의 경우 3단계에서 측정된 대사별 타이밍에서 voice.srt를 작성하세요 — 숫자는 이미 존재합니다. 이것은 포맷팅 단계이지 새로운 작업이 아닙니다.

verify.png를 읽으세요 — 인코딩된 출력을 확인하는 것이 브라우저가 아닌 요점입니다. 그런 다음 스크래치 시트와 프레임 디렉토리를 삭제하세요.

성공 기준: ffprobe가 예상 지속 시간, 예상 치수(사용자가 종횡비를 변경하지 않는 한 1080×1920), nb_frames == fps × duration을 보고합니다. 내레이션 작품의 경우 오디오 스트림이 있고 지속 시간이 음성 베드와 일치하며 voice.srt가 존재합니다. verify.png가 비트 시트와 일대일로 일치합니다. 끝이 누락된 짧은 파일은 일반적으로 -shortest가 오래된 음성 트랙을 만났음을 의미합니다 — references/audio.md 참조.

8. 전달

비디오 옆에 README를 작성하세요: 비트 시트, 리브랜딩 상수, 렌더 명령어, 두 가지 하니스 주의사항. 그런 다음 사용자에게 보고합니다:

  • 파일 위치와 정확한 사양(크기, 지속 시간, fps, 내레이션 또는 무음 여부 — 및 사용된 TTS 음성, 재생성 가능하도록)
  • 내레이션 작품의 voice.srt 경로, Shorts/Reels/TikTok이 비디오와 함께 업로드로 허용한다는 점
  • 비트 표
  • 모든 플레이스홀더와 임의 생성 숫자, 명시적으로 호출 — 브랜드 이름, URL 및 모형에 표시된 모든 메트릭. 주장이 방어 가능해야 하는 경우 게시 전에 조작된 수치를 교체해야 한다고 분명히 말하세요.
  • 공유 가능한 링크가 없음 — 사용자가 호스팅을 요청하지 않는 한 로컬 파일입니다.

열기를 제안하세요: open promo.mp4.

규칙: 명시적 승인 없이 커밋하거나 게시하지 마십시오. 비디오를 어디에도 업로드하는 것을 출력의 부작용으로 만들지 마십시오.

성공 기준: 사용자가 파일 경로, 플레이스홀더 내용 및 변경 방법을 알고 있습니다.

규칙

하드 제약 조건. 각각은 이 파이프라인이 이미 생성한 실패입니다.

  1. 기본적으로 내레이션, 절대 음악 없음. 사용자가 무음 작품을 요청하지 않는 한 음성 해설을 작성하고 타임라인을 제어하도록 하세요. 음악 및 사운드 디자인은 명시적으로 요청되지 않는 한 꺼져 있어야 합니다 — 라이선스 트랙을 제공할 수 없으며 스트리밍 사이트에서 오디오를 가져오지 마십시오. 그럼에도 불구하고 음소거 재생을 가정하세요: 모든 음성 해설 주장은 화면 텍스트로 미러링되며, 내레이션 작품에는 voice.srt가 함께 제공됩니다. 무음 작품을 제공할 때는 보고 시 "무음"이라고 말하여 조용한 재생이 버그로 읽히지 않도록 하세요.

  2. 요소당 하나의 애니메이션, 진입 → 유지 → 종료 포함. fill: 'both'가 있는 두 개의 개별 WAAPI 애니메이션은 충돌합니다: 종료 클립은 t = 0에서 첫 번째 키프레임을 적용하여 요소를 전체 비디오 동안 보이게 고정합니다. io() 헬퍼는 이를 방지하기 위해 독점적으로 존재합니다. 증상: 장면의 모든 것이 장면 시작에 한꺼번에 나타나는 대신 애니메이션으로 들어옵니다.

  3. 연속적인 텍스트는 다음이 들어오기 전에 완전히 종료되어야 합니다. 교차 페이드 중간에 화면에 두 개의 읽을 수 있는 줄이 있으면 전환이 아닌 렌더링 버그로 읽힙니다. N번째 줄의 종료가 N+1번째 줄의 입장 시작 전에 완료되도록 예약하세요.

  4. 결정론은 협상 불가입니다. RNG를 시드하세요. Date.now(), Math.random()을 절대 호출하지 마세요.

  5. 모든 동적 데이터(타이머, 카운터, 진행 막대, 게이지, 통계, 포인트, 단계)는 합성되어야 합니다. 화면 시간 범위에 걸쳐 무작위로 생성되거나 파생된 값입니다. 텍스트 및 수치 데이터를 실제로 생성하지 마십시오. 플레이스홀더가 있음을 나타내는 방해가 되지 않는 [demo data] 배지를 포함하세요.

  6. type 태그와 함께 하나의 표준 Google Fonts 스타일 링크만 사용하세요. @import 또는 @font-face는 작동하지만 Playwright가 기다리는 이벤트를 방출하지 않아 첫 번째 프레임 시간 이후 로드되므로 텍스트가 사라집니다. 글꼴이 로드되었는지 확인하는 유일하게 신뢰할 수 있는 방법은 document.fonts.ready를 기다리는 것입니다 — scene-starter.html은 이미 이 작업을 수행합니다. 글꼴을 다시 로드하지 마십시오.

  7. --at 모드가 있어야 하며 정확해야 합니다. render.py 템플릿은 seek(sec) 호출과 함께 하나를 구현합니다 — 이를 제거하거나 시간을 반올림하지 마십시오. 부정확한 타임스탬프 디버깅은 사용자와의 모든 신뢰를 잃습니다.

  8. 장면 전환을 위해 투명도는 사용하지 마십시오 — 흰색 또는 검은색을 사용하세요. 키잉 목적으로 요소를 rgba(0,0,0,0)로 설정하지 마십시오 — 컴포지팅은 잘못된 검정색으로 병합됩니다(Chrome 버그 1441907 참조). 배경색을 사용하거나 요소를 프레임 밖으로 이동시키거나 visibility: hidden을 사용하세요. 불투명도는 페이드에만 사용하세요.

  9. 내레이션을 장면 비율로 측정하세요. 실제 음성 속도는 템플릿 대사 시간과 다른 경우가 많습니다. openai/tts 또는 원하는 TTS를 사용하여 대사를 생성하고, 오디오 파일을 다운로드/저장하고, vo/에 저장하고, 지속 시간을 추출하세요. ffprobe를 사용하십시오 — 정확한 프레임 시간. 그런 다음 측정된 지속 시간을 사용하도록 비트 시트를 조정하세요. 30초 슬롯에 맞추기 위해 읽기 속도를 높이지 마십시오 — 편안한 전달이 전문적입니다.

  10. 리소스 URL이 작동하는지 확인하세요. 빌드 전에 font.googleapis.com, cdnjs.cloudflare.com 등을 컬(curl)하거나 가져오세요. 빌드 도중 실패는 디버그하기 어렵습니다.

  11. 출력 비디오를 확인하세요 — 브라우저가 아닙니다. Chromium은 디스플레이 P3 색 공간에서 렌더링되며, 이는 sRGB 렌더링과 다르며 최종 비디오에 번짐/채도 저하를 유발할 수 있습니다. verify.png가 브라우저 미리보기와 어떻게 다른지 확인하세요.

  12. 접촉 시트 축소판에서 중요한 세부 사항을 읽지 마십시오. 모든 모형, 픽토그램 또는 텍스트가 많은 장면을 --at에서 전체 크기로 개별적으로 확인하세요. 축소판에서 인식 가능성은 속일 수 있습니다.

  13. 시간이 0에 있는 애니메이션은 즉시 적용됩니다. t = 0에 세 번째 애니메이션 프레임(33ms)을 배치하지 마십시오. 첫 번째 프레임이 렌더링될 때 이미 진행 중입니다. t = 0.03을 시작으로 사용하여 예상치 못한 모양을 방지하세요.

  14. 하드웨어 가속을 비활성화하세요. --disable-accelerated-2d-canvas 및 관련 플래그가 없으면 Playwright는 GPU로 오프로드하여 픽셀 일치 결과를 망가뜨릴 수 있습니다. 템플릿 render.py는 이러한 플래그를 설정합니다 — 제거하지 마십시오.

  15. 모든 프레임의 부분이 아닌 전체를 확인하세요. "이 프레임은 완벽해 보입니다"는 충분하지 않습니다 — 모든 프레임을 보거나(접촉 시트를 통해) 합리적으로 확인할 수 있는 set을 확인했습니다.

  16. 확인된 도구만 사용하세요. Playwright의 Chromium, ffmpeg, ffprobe. puppeteer가 아닙니다.

  17. 외부 리소스를 절대 가져오지 마세요 — 로컬에 복사하거나 포함시키세요. Google Fonts 스타일 시트는 예외입니다.

  18. 네트워크 액세스 없이 로드되는지 테스트하세요. 공급자가 차단된 경우 오프라인에서 페이지가 중단되지 않는지 확인하십시오. Playwright가 오프라인인 상태에서 한 번 실행하세요. (page.context.setOffline(true))

  19. 도메인 속도 제한을 존중하세요. 여러 Google Fonts @import 스타일 시트를 포함하지 마십시오 — 특정 패밀리에만 가져오는 하나의 URL을 사용하세요.

  20. 시드된 RNG는 이 파이프라인에 의해 생성되지 않은 요소를 포함하여 모든 결정적이지 않은 것을 대체합니다. Google Fonts 스타일 시트는 콘텐츠가 아니라 발견 가능성 — 이것은 괜찮은 결정적이지 않은 것입니다. 애니메이션 delay에서의 Math.random()은 그렇지 않습니다.

관련 스킬