Communitygithub.com

scenario-motion-loops

원하는 브랜드 색상으로 제목 배경, AI 샷 사이의 끊김을 메우는 루프, 범퍼, 전환 또는 도형 애니메이션 등 매끄러운 반복 모션 그래픽 비디오를 생성합니다. 선택적으로 Scenario MCP의 마스코트, 제품 또는 캐릭터를 합성할 수 있습니다.

scenario-motion-loops란 무엇인가요?

이 스킬은 완전히 코드 기반으로 매끄러운 반복 모션 그래픽 비디오를 제작하는 강력한 도구입니다. 시간의 순수 함수로 작동하며, 모든 모션 주기가 루프 길이(12초)를 정확히 나누어야 하므로 프레임이 완벽하게 일치하고 이음새(seam)가 없습니다. 개발자는 Canvas 2D HTML 파일 하나로 루프를 작성하고, 브라우저에서 실시간 미리보기를 확인한 후, 모션 블러, 슈퍼샘플링 및 H.264 BT.709 인코딩이 적용된 12초 분량의 1920x1080 MP4 파일로 렌더링할 수 있습니다. 또한 Scenario MCP를 통해 코드로는 구현하기 어려운 마스코트, 제품 또는 캐릭터를 투명 배경 컷아웃으로 가져와 루프 위에 합성할 수 있으며, 필요 시 AI 비디오 샷을 생성하여 ffmpeg로 합성할 수도 있습니다. Node 18+, Playwright, ffmpeg/ffprobe가 필요하며, `--check` 플래그를 통해 결정론적 동작(Determinism)과 루프 이음새를 자동으로 검증하여 버그 없는 완벽한 루프를 보장합니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/DawitLemmaBalcha/motion-graphics-studio/tree/HEAD/skills/motion-graphics/setup/templates/scenario-motion-loops

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

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

문서

코드로 만드는 매끄러운 모션 루프, Scenario MCP의 오브젝트와 함께

개요

루프는 시간의 순수 함수입니다. draw(ctx, w, h, t, P)는 t초 시점의 프레임을 그리며, 모든 모션은 루프 길이(12초)를 정확히 나누는 주기로 반복됩니다. 따라서 12초에서의 프레임은 0초에서의 프레임과 동일하여 클립이 이음새 없이 반복됩니다. 생성되는 것은 없습니다: 왜곡이나 깜빡임이 없으며, 하나의 색상을 바꾸면 전체 브랜드 색상이 바뀌고, 동일한 코드가 어떤 크기에서든 렌더링됩니다. scenario.com의 Motion Loops 탐색에서는 이 방식으로 제작된 80개의 루프(배경 40개, 도형 애니메이션 40개)와 각각의 코드를 볼 수 있습니다. scripts/loop-template.html에는 이러한 루프를 작성하는 데 사용된 동일한 헬퍼(M.*), 팔레트(P) 및 tile(...) 등록 함수가 포함되어 있어, 이 템플릿 위에서 작성된 타일 코드가 변경 없이 실행됩니다.

Scenario MCP는 코드로 그릴 수 없는 것, 즉 사용자의 오브젝트를 만듭니다. 마스코트, 제품 또는 캐릭터가 투명 배경 컷아웃으로 Scenario에서 나오며, 루프 페이지는 이를 루프 자체의 클록에 따라 루프 위에 그리므로 동일한 모션 블러를 받고 합성 결과도 여전히 반복됩니다. 실제로 움직이는 오브젝트의 경우, 해당 컷아웃으로 AI 비디오 샷을 생성하고 Scenario에서 배경을 제거한 후, ffmpeg로 렌더링된 루프 위에 샷을 배치합니다. 루프 자체는 모델이 전혀 필요 없고 렌더링 비용이 들지 않습니다.

Node 18 이상, Playwright(npm install playwright, npx playwright install chromium; 또는 Google Chrome이 설치된 경우 --channel chrome), ffmpeg 및 ffprobe가 필요합니다. Scenario MCP는 오브젝트가 필요할 때만 사용합니다. 연결, 모델 선택 및 생성 루프: scenario 스킬이 설치되어 있다면 해당 스킬을, 그렇지 않으면 references/scenario-mcp.md를 참조하세요.

빠른 참조

cp scripts/loop-template.html loop.html            # 루프 파일 하나당 하나의 루프: 설정, draw(), 오버레이
# loop.html을 브라우저에서 열기: 실시간 미리보기; ?t=3으로 고정, ?tone=accent 또는 ?tone=light로 톤 전환
node scripts/render-loop.mjs loop.html --check     # 결정론적 동작 및 루프 이음새 확인, 비디오 없음
node scripts/render-loop.mjs loop.html --stills look --at 0,3,6,9             # 확인용 스틸 이미지
node scripts/render-loop.mjs loop.html --out loop.mp4                          # 12초, 1920x1080, 24fps
node scripts/render-loop.mjs loop.html --params "overlay=subject.png" --out loop.mp4   # 컷아웃 포함
node scripts/render-loop.mjs loop.html --width 1080 --height 1920 --out loop-9x16.mp4  # 세로
node scripts/render-loop.mjs --qa loop.mp4 composite.mp4   # 모든 MP4의 이음새 및 포맷 확인

Playwright가 설치된 폴더에서 실행하세요. 기존 파일은 --force 없이 덮어쓰지 않습니다. 페이지 검사는 동일한 순간을 두 번 렌더링하여(일치해야 함) 정확히 12초에서의 프레임과 0초에서의 프레임을 비교하고, 루프 지점을 넘어서는 단계의 움직임을 주변 및 다른 주기 경계에서의 움직임과 비교합니다. 렌더링은 PASS가 출력될 때만 인코딩을 허용합니다. --ignore-seam은 루프 지점에 고정되도록 설계된 컷에만 사용합니다.

규칙이유
모든 주기는 12초를 정확히 나눔(1, 1.5, 2, 3, 4, 6, 12); M.phase(t, period, offset) 사용12초에서의 프레임이 0초에서의 프레임과 동일함
스크롤은 주기당 패턴 반복 횟수의 정수 배만큼 이동함분수 반복은 이음새에서 점프 발생
무작위성은 M.rand(i, salt)에서만 사용; 프레임 간 Math.random, Date 또는 상태 사용 금지모션 블러 및 검사가 프레임을 순서 없이 렌더링함
크기는 u = h / 100에서, 개수는 w에서 계산16:9, 9:16, 1:1 및 썸네일 크기에서 정상 작동
색상은 P에서만 사용(bg, fg, fg2, mid, accent, paper, ink), 브랜드 색상당 세 가지 톤BRAND 변경으로 리브랜딩; 톤 변경으로 대비 조절
이징은 M.ease 사용, 예상, 오버슛 및 홀드 포함; 스크롤에만 일정 속도 사용기계적인 움직임이 아닌 디자인된 움직임

80개의 루프와 함께 제공된 렌더링 설정 및 스크립트 기본값: 24fps, 180도 셔터에 8개의 모션 블러 서브 프레임, 2x 슈퍼샘플링, H.264 High, CRF 16, 4:2:0, BT.709 제한 범위, faststart. 루프를 닫는 패턴, 깊이 트릭 및 검토 습관: references/loop-craft.md.

Scenario MCP 단계호출
연결, 팀 및 프로젝트 선택teams_list (여러 개 있을 경우 사용자에게 질문)
사용자 아트 가져오기upload_asset, 각 파트의 curl PUT, upload_asset_complete
모델 선택recommend (txt2img, img2img, img2video, video2video), 또는 search
모델 입력값 읽기model_schema_get
가격 확인 후 사용자 동의 후 실행dry_run: true로 model_run, 그 다음 model_run 및 jobs_wait
결과 가져오기asset_download, 그 다음 curl -L -o

작업 예제: 코드 루프 위에 떠 있는 브랜드 마스코트

목표: 브랜드 색상의 12초 매끄러운 1920x1080 루프에 브랜드 마스코트가 떠 있는 버전, 그리고 선택적으로 마스코트가 손을 흔드는 버전을 만듭니다.

  1. 연결. teams_list를 호출합니다. 여러 팀이나 프로젝트가 반환되면 어느 것을 사용할지 묻고, 해당 team_id와 project_id를 이후 모든 호출에 전달합니다(로그인된 계정의 경우 search, model_schema_get 및 model_run은 이것 없이 실행을 거부합니다).

  2. 먼저 루프를 빌드합니다(로컬, 무료). cp scripts/loop-template.html mascot-loop.html을 실행하고, BRAND.accent를 브랜드 색상으로 설정하고 예제 타일(원근 바닥, 카메라를 향해 흐르는 그리드)을 유지하거나 고유한 draw()를 작성합니다. 파일을 열어 미리본 다음:

    node scripts/render-loop.mjs mascot-loop.html --check
    node scripts/render-loop.mjs mascot-loop.html --stills look --at 0,3,6,9
    

    스틸 이미지를 확인합니다. --check는 PASS로 끝나야 합니다.

  3. 마스코트를 가져옵니다. 사용자가 파일로 가지고 있는 경우 업로드합니다:

    {
      "file_name": "mascot.png",
      "content_type": "image/png",
      "kind": "image",
      "file_size": 482113
    }
    

    (file_size는 wc -c mascot.png로 확인.) 반환된 URL에 curl로 PUT한 다음, upload_asset_complete를 {"upload_id": "<upload id>"}와 함께 호출하고 자산 ID를 보관합니다.

  4. 모델을 선택합니다. recommend를 다음으로 호출합니다:

    {
      "capability": "img2img",
      "prompt": "참조 이미지의 마스코트, 전신, 3/4 뷰, 가볍게 떠 있는 포즈, 깨끗한 가장자리로 투명 배경에 컷아웃, 그림자 없음, 텍스트 없음",
      "limit": 5
    }
    

    파일이 없으면 "capability": "txt2img"를 사용하고 마스코트를 설명합니다. next_step.type이 ask_user이면 옵션을 보여주고 기다립니다. 스키마에 투명 배경 옵션이 있는 모델을 선호합니다. 그렇지 않으면 이후 배경 제거 단계를 계획합니다.

  5. 스키마를 읽고 가격을 확인합니다. model_schema_get을 {"model_id": "<recommend에서 받은 id>"}로 호출합니다. 스키마에서 매개변수를 빌드합니다: 참조 이미지 필드는 업로드된 자산 ID를 사용하고(스키마에서 지정하는 경우 배열로), 투명 배경 옵션을 설정합니다. 그런 다음:

    {
      "model_id": "<recommend에서 받은 id>",
      "dry_run": true,
      "parameters": {
        "prompt": "<위의 프롬프트>",
        "<참조 이미지 필드>": ["<마스코트 자산 id>"],
        "<배경 필드>": "transparent"
      }
    }
    

    사용자에게 가격을 알리고 동의를 기다립니다.

  6. 실행 및 다운로드. 동일한 매개변수로 model_run을 "wait": false와 함께 호출한 다음, jobs_wait를 {"job_ids": ["<job id>"]}로 호출합니다. 그런 다음 asset_download를 {"asset_id": "<asset id>", "format": "png"}로 호출하고 curl -L -o subject.png "<url>"을 mascot-loop.html의 폴더에 실행합니다. PNG를 루프의 배경색 위에서 100%로 엽니다: 어두운 톤에서 윤곽선의 후광이 보이면 숨기지 말고 다시 생성합니다.

  7. 캔버스에 합성하고 렌더링합니다.

    node scripts/render-loop.mjs mascot-loop.html --params "overlay=subject.png" --stills look --at 0,0.75,1.5,2.25 --force
    node scripts/render-loop.mjs mascot-loop.html --params "overlay=subject.png" --out mascot-loop.mp4 --psnr 4
    

    drawOverlay()는 마스코트를 3초 주기의 상하 움직임과 6초 주기의 좌우 움직임으로 떠 있게 하고 접촉 그림자를 추가하며, 모든 주기가 12를 나누므로 합성 결과도 여전히 반복됩니다. 크기와 배치는 여기서 조정합니다. 스크립트는 페이지를 확인하고, 288프레임을 렌더링하고, 인코딩한 다음 파일의 루프 지점을 확인합니다. --psnr은 인코딩된 한 프레임을 무손실 렌더링과 비교합니다.

  8. 선택 사항: 마스코트가 움직이는 샷. recommend를 "capability": "img2video"로 호출하고, 컷아웃의 자산 ID를 시작 이미지로, 프롬프트는 "마스코트가 손을 흔들고 고개를 돌리며, 평평한 단색 배경, 고정 카메라, 컷 없음"으로 설정합니다. 스키마, 가격 확인, 실행, jobs_wait, 다운로드. 그런 다음 recommend를 "capability": "video2video"로 호출하고 "이 클립에서 배경을 제거하고 알파 채널과 함께 오브젝트 유지"로 설정하고, 출력으로 알파가 포함된 WebM VP9을 선택합니다. 스키마, 가격 확인, 실행, 다운로드. --params overlay=... 없이 루프를 한 번 더 렌더링하고(--out loop-plain.mp4), ffmpeg로 샷을 그 위에 배치합니다(명령어는 references/scenario-mcp.md에 있음). 합성물은 샷의 길이와 같으며, 샷이 반복되지 않으면 매끄러운 루프가 아닙니다.

  9. 전달 HTML(루프는 계속 편집 가능), MP4, 스틸 이미지 및 모든 합성물을 전달합니다.

일반적인 실수

  • 12초에서의 이음새 점프. 12를 나누지 않는 주기(5초 주기) 또는 2.5회 반복 이동하는 스크롤. --check는 SEAM JUMP를 보고합니다(12초에서의 프레임이 0초에서의 프레임과 다름). 주기를 수정하고, 끝을 교차 페이드하지 마십시오.
  • 타일에서 Math.random 또는 Date 사용. 동일한 t에 대해 다른 프레임이 생성되고, 모션 블러 서브 프레임이 일치하지 않으며 루프가 닫히지 않습니다. --check는 NOT DETERMINISTIC을 보고합니다. 모든 것을 t와 M.rand(i, salt)에서 계산하십시오.
  • 16진수만 읽는 색상 헬퍼. P.mid와 M.mixColor는 rgb() 문자열을 반환하며, 16진수 전용 파서는 이를 자동으로 검은색으로 변환합니다. 템플릿의 M.rgba 및 M.mixColor는 둘 다 읽습니다.
  • 빠른 움직임에서의 스트로보 효과. 8개의 서브 프레임은 전체 프레임 푸시에 충분하지 않습니다. 계단식 복사본이 나타납니다. 빌드의 전체 페이지 스와이프는 40개가 필요했습니다. 매우 빠른 루프의 경우 --samples를 높이십시오.
  • 와이어프레임이 잡음으로 읽히는 경우. 3D 웨이브 메쉬가 그랬습니다. 숨은선 제거 능선(각 행이 자신 아래의 배경을 채우고 먼 곳에서 가까운 곳으로 그려짐)으로 다시 빌드하니 지형으로 읽혔습니다.
  • 깊이를 두 번 나누는 경우. 초점 거리를 깊이로 다시 조정하는 투영은 장면을 중앙으로 축소시킵니다. M.proj로 한 번만 투영하십시오.
  • 1.5초마다 스틸 이미지로 3초 주기 검토. 그것은 2개의 포즈만 보여줍니다. 하나의 주기 내부와 루프 지점의 양쪽을 샘플링하십시오(--at 11.9,11.95,0,0.05).
  • 모든 플래그를 버그로 처리. 디자인된 스냅(팝, 버스트) 또는 루프 지점의 홀드는 이음새 또는 글리치 감지기를 트리거할 수 있습니다. 먼저 프레임을 보십시오. 스크립트는 루프 지점을 주변의 움직임 및 다른 주기 경계와 비교하므로 대부분의 경우를 피합니다: 빌드의 80개 루프 모두 통과했습니다.
  • 레벨 또는 카운터가 잘못 래핑되는 경우. 주기로 인덱싱되는 모든 것은 M.mod로 래핑해야 합니다. 빌드에서 페이지 카운터가 수정될 때까지 루프 지점에서 "06 / 05"로 표시되었습니다.
  • 하나의 톤에서 낮은 대비. 색상을 추가하는 대신 해당 루프의 톤(어두움, 강조, 밝음)을 변경하십시오.
  • 디스크의 오버레이 PNG. file://에서 열리고 로컬 이미지를 그린 다음 픽셀을 다시 읽는 페이지는 이미지가 캔버스를 오염시키기 때문에 실패합니다. render-loop.mjs는 로컬 주소를 통해 폴더를 제공합니다. 브라우저 미리보기는 표시만 하므로 영향을 받지 않습니다.
  • 글꼴 로드 전 텍스트. 캔버스 텍스트는 웹 글꼴을 기다리지 않습니다. 첫 번째 프레임 전에 document.fonts.load(...)를 await하거나 루프에 텍스트를 그리지 마십시오.
  • 비트레이트 추구. 평평한 색상에서 x264는 매우 적은 비트를 소비하고 파일이 작아 보입니다. 빌드에서 PSNR은 인코더가 거의 손실을 추가하지 않음을 보여주었습니다. 유일한 실제 손실은 얇은 채도가 높은 선의 4:2:0 크로마입니다. --psnr로 확인하고, 비트레이트를 높이는 대신 얇은 색상 선을 두껍게 만드십시오.
  • VP9 샷의 알파 손실. ffmpeg의 내장 VP9 디코더는 알파를 무시합니다. -i shot.webm 앞에 -c:v libvpx-vp9를 넣으십시오.
  • 비디오 모델로 루프 만들기. 생성된 클립의 마지막 프레임이 첫 번째 프레임과 정확히 일치하는 경우는 드뭅니다. 첫 번째 것을 사용하지 마십시오.

Scenario MCP 참조

연결, 팀 선택, 자산 업로드, 모델 추천, 스키마 읽기, 가격 확인, 실행, 다운로드에 대한 자세한 내용은 references/scenario-mcp.md를 참조하세요.

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

관련 스킬