Communitygithub.com

mirac221/frame-judge

명령 전용 스킬입니다. 사용자가 이름을 명시적으로 호출할 때만 실행하세요. 일반 UI, 애니메이션 또는 비디오 작업을 위해 자체적으로 로드하지 마십시오.

frame-judge란 무엇인가요?

frame-judge는 AI가 생성한 시각적 결과물을 사용자의 요청과 비교하여 객관적으로 평가하는 비평 시스템입니다. 개발자가 코드와 의도를 공유하지 않고 순수하게 결과물의 픽셀만을 기준으로 비평하는 별도의 비평가 역할을 수행합니다. 이 스킬은 Claude Code, Codex, Cursor 등 다양한 플랫폼에서 사용할 수 있으며, Node 18+ 스크립트로 구성되어 있어 별도의 설치 과정이 필요 없습니다. 핵심 동작 방식은 사용자의 요청을 그대로 잠그고, 결과물을 렌더링 및 캡처한 후, 코드와 분리된 리뷰 패킷을 생성합니다. 그 다음 새로운 하위 에이전트(비평가)가 이 패킷만을 보고 평가하며, 게이트 스크립트가 평가의 유효성을 검증합니다. 기본적으로 최대 3라운드까지 반복되며, 각 라운드마다 새로운 비평가가 투입되어 이전 평가의 영향을 받지 않도록 합니다. 이 도구의 가치는 개발자가 의도한 결과물과 실제 렌더링된 결과물 사이의 차이를 발견하는 데 있습니다. 예를 들어, 애니메이션 개발자는 '완벽한 보행 주기'를 상상하지만, 비평가는 실제 픽셀에서의 끊김이나 부자연스러움을 지적할 수 있습니다. 'unsloppy' 모드를 통해 AI의 일반적인 실수 패턴을 사전에 조사하여 더 나은 결과물을 만들도록 도와줍니다.

지원 대상✓Claude Code✓Codex CLI✓Cursor✓Antigravity
npx skills add https://github.com/mirac221/frame-judge/tree/HEAD

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

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

문서

frame-judge은(는) 무엇을 하나요?

당신은 자신의 시각적 작업을 평가할 수 없습니다.

당신이 만들고 렌더링합니다. 그런 다음 별도의 비평가가 실제로 화면에 나온 결과물을 사용자가 실제로 요청한 내용과 대조하여 평가합니다. 비평가는 당신의 코드, 추론 과정, 또는 결과물에 대한 당신의 의견을 절대 볼 수 없습니다. 작업이 통과되거나 라운드 제한에 도달할 때까지, 당신은 그 작업을 '완료', '다듬어짐', '부드러움', '아름다움'이라고 부를 수 없습니다.

이유: 코드를 작성한 모델은 자신의 의도를 출력에 읽어 넣습니다. 실제로 렌더링되는 보행 주기가 아니라, 자신이 의도한 보행 주기를 '봅니다'. 오직 픽셀과 사용자의 말만 받는 비평가는 그렇게 할 수 없습니다. 반드시 '봐야' 합니다.

<skill>은 이 파일이 있는 폴더를 의미합니다 (Claude Code의 경우: ${CLAUDE_SKILL_DIR}). 스크립트는 설치 단계 없이 일반 Node 18+로 동작합니다. 작업 디렉토리 아래 .frame-judge/ 디렉토리에 상태를 유지합니다.

루프

단계내용담당자
0사용자의 요청을 있는 그대로 잠급니다당신
0b"unsloppy?"라고 묻습니다. '예'인 경우, 스카우트가 피해야 할 AI 기본값을 조사합니다당신, 사용자, 스카우트
1제작당신
2렌더링 및 캡처: 스크린샷, 프레임 시트, 모션 트레일스크립트
3기계적 자가 점검: 렌더링됨, 빈 화면 없음, 런타임 오류 없음당신
4코드가 없는 리뷰 패킷 번들 생성스크립트
5플랫폼이 허용한다면, 비평가가 실행될 모델을 묻습니다 (한 번만)당신, 그 다음 사용자
6비평가가 번들을 검토합니다새로운 하위 에이전트
7게이트가 검토를 검증하고 결정합니다스크립트
8모든 '반드시 수정' 사항에 응답한 후 2단계로 돌아갑니다당신
9비평가의 평결을 보고합니다. 당신의 의견이 아닙니다당신

기본 제한: 3라운드의 비평.

0. 브리프 잠그기

node <skill>/scripts/judge.mjs init --brief-file request.txt --kind frontend,motion

인라인 텍스트의 경우 --brief "..."을, stdin에서 읽으려면 --brief-file -를 사용하세요.

  • 있는 그대로. 사용자의 메시지를 작성된 그대로 저장합니다: 오타, 대문자, 모든 것. 절대 의역, 요약, 또는 "명확히" 하지 마십시오. 비평가는 당신의 해석이 아닌 사용자의 단어를 기준으로 판단합니다.
  • 사용자의 후속 설명은 judge.mjs brief --add "<정확한 단어>"로 추가합니다. 당신의 추정은 절대 넣지 마십시오.
  • 사용자가 제공한 참조 이미지: --ref mock.png (반복 가능)를 추가하여 비평가가 참조 이미지와 비교할 수 있게 합니다.
  • **--kind**는 루브릭을 선택합니다: frontend는 페이지와 UI용, motion은 모든 애니메이션용, video는 클립과 편집용입니다. 캡처에서 자동 감지하려면 비워두세요.
  • --critic-model 사용자가 이미 모델을 지정한 경우 사용합니다.

이 명령은 .frame-judge/ (자체적으로 git-ignores 됨)를 생성하고 brief.md와 ledger.json을 만듭니다. 원장(ledger)은 컨텍스트 압축에서도 유지됩니다. 추적을 놓친 경우 judge.mjs status를 실행하세요.

0b. unslop 모드에 대해 묻기 (빌드 전)

사용자에게 다음 문구로 한 번 질문하세요:

unsloppy로 하시겠습니까? (실험적: 품질이 저하될 수 있고 더 많은 토큰을 사용합니다)

Claude Code에서는 AskUserQuestion을 사용하여, 5단계의 비평가-모델 질문과 같은 프롬프트에서 질문하세요. 다른 곳에서는 채팅에서 질문하세요. 사용자가 이미 말했다면 건너뛰세요.

  • 아니오: 계속 진행합니다. Unslop은 기본적으로 꺼져 있습니다.
  • 예:
    1. judge.mjs set unslop on을 실행한 다음, judge.mjs scout를 실행합니다. 슬롭 스카우트를 위한 메시지가 출력됩니다: AI가 이런 종류의 요청을 어떻게 잘못 처리하는지 알아내기 위해 웹 검색을 사용하는 새로운 하위 에이전트입니다.
    2. 해당 메시지를 스카우트에게 보내고 다른 것은 보내지 마십시오. 비평가와 동일한 규칙이 적용됩니다: 새로운 에이전트, 포크 없음, 아무것도 추가하지 않음. 설정된 경우 비평가의 모델을 사용하세요.
    3. 스카우트의 응답을 저장한 다음, judge.mjs avoid --file <reply>를 실행합니다. 이 명령은 실제 출처가 없는 목록을 거부합니다.
  • 웹 검색을 사용할 수 없음: unslop을 여기서 실행할 수 없다고 사용자에게 알리고, 계속 진행합니다.

회피 목록은 .frame-judge/avoid.md에 저장되며 모든 리뷰 번들에 포함되어 비평가가 작업을 이 목록과도 확인합니다.

"실험적"이라고 하는 이유는 기본값에서 벗어나면 빌드가 이상한 선택으로 이어질 수 있고, 스카우트가 웹 검색을 사용하는 추가 에이전트 실행 비용이 들기 때문입니다.

1. 제작

unslop이 켜져 있으면 먼저 .frame-judge/avoid.md를 읽으세요.

  • 각 패턴을 피해 설계하세요. 단순히 반대로만 하지 마십시오: 목표는 단지 '다른' 작업이 아니라 브리프에 맞는 작업입니다.
  • 사용자가 명시적으로 요청한 것은 목록보다 우선합니다.

제작 전에, references/craft.md의 해당 미디어 섹션을 세션당 한 번 읽으세요. 비평가들이 가장 많이 지적하는 사항들(간격, 타이포그래피, AI 템플릿 특성, 이징, 보행 주기, 비디오 속도)을 다룹니다.

애니메이션의 경우, 시간을 명시적 입력으로 만드세요: 탐색 가능한 타임라인이나 window.frameJudgeSeek(ms) 훅을 제공하십시오. 이렇게 하면 캡처가 프레임 단위로 정확해지고, HTML을 비디오로 무료로 변환해 줍니다.

2. 렌더링 및 캡처

페이지 및 UI (Playwright 필요; 설정은 references/capture.md 참조):

node <skill>/scripts/capture-page.mjs http://localhost:5173 --out .frame-judge/cap/page

기본값은 데스크탑 1440×900, 태블릿 768×1024, 모바일 390×844이며, 화면별로 캡처합니다. 옵션:

  • --actions states.json hover, 메뉴 및 오류 상태용
  • --color-scheme dark
  • --reduced-motion
  • URL 뿐만 아니라 로컬 파일도 작동합니다

페이지의 애니메이션. 프레임 단위로 정확하며 (가짜 시계 + Web Animations 탐색) MP4로 인코딩합니다:

node <skill>/scripts/capture-page.mjs scene.html --out .frame-judge/cap/anim --animate 3000 --fps 30 --selector "#hero"

모든 비디오, 해당 MP4를 포함:

node <skill>/scripts/video-frames.mjs .frame-judge/cap/anim/animation.mp4 --out .frame-judge/cap/anim-views --as motion

결과물:

  • 뷰포트 조각: 다운스케일되어 뭉개질 수 있는 하나의 거대한 전체 페이지 이미지 대신 제공됩니다.
  • 액션 파일의 상태 샷.
  • 타임스탬프가 포함된 콘택트 시트.
  • 필름스트립: 기본적으로 12fps로 샘플링된 프레임과 스크립트가 감지한 갑작스러운 점프 또는 지연 주변의 전체 속도 스트립 (--motion-fps source는 모든 곳의 모든 프레임을 제공). 샘플링은 한 프레임 글리치가 타일 사이에 빠질 수 있음을 의미하므로 이벤트 감지가 존재합니다.
  • 모션 트레일: 정지해야 할 것은 선명하게 유지되고, 움직이는 것은 흐려집니다.
  • 객관적 수치: 지속 시간, fps, 검은색 또는 정지된 세그먼트, 수평 오버플로, 깨진 이미지.

사용자가 경험할 것을 캡처하세요: 그들이 사용할 모든 뷰포트, 중요한 상태, 전체 애니메이션. 비평가는 당신이 보여주지 않은 것을 지적할 수 없습니다. 추한 부분을 빼는 것은 이 스킬이 막고자 하는 바로 그 속임수입니다.

3. 기계적 자가 점검

비평가 라운드를 시작하기 전에 이진적인 것들을 확인하고 수정하세요:

  • 렌더링됨
  • 빈 프레임이나 검은 프레임 없음
  • 각 capture.json의 builder_only에 아무것도 없음 (콘솔 오류, 실패한 요청)
  • 올바른 지속 시간과 크기
  • horizontal_overflow_px와 broken_images가 0임

이것이 전체 목록입니다. 당신이 '괜찮아 보인다'고 판단하여 비평가를 건너뛸 수 없습니다.

4. 번들

node <skill>/scripts/judge.mjs bundle .frame-judge/cap/page .frame-judge/cap/anim-views

이 명령은 .frame-judge/round-N/bundle/을 작성합니다. 시각적 파일(png, jpg, webp, gif 및 --include-video를 전달한 경우 비디오)과 다음 텍스트 파일만 포함합니다:

  • brief.md, 코드 블록이 제거됨
  • 루브릭
  • CRITIC.md, 비평가의 지침
  • manifest.json, 인용 가능한 아티팩트 ID 포함
  • prior.json, 2라운드부터: 당신의 "수정됨" 주장 없이 공개된 문제점들. 비평가가 스스로 확인할 수 있도록 합니다.

스크립트는 '반드시 수정' 사항에 응답하지 않았거나 라운드 제한을 초과한 경우 새 라운드를 열지 않습니다. 비평가에게 보낼 정확한 메시지를 출력합니다.

이미지 예산: 라운드당 20개 이하의 이미지를 목표로 하세요. Claude는 한 요청에 20개 이상의 이미지가 있으면 이미지당 제한을 강화합니다. 모든 이미지는 약 ⌈w/28⌉×⌈h/28⌉ 토큰이 소요됩니다. 1440×900 샷은 약 1.7k입니다. 콘택트 시트와 필름스트립은 12~16프레임을 하나의 이미지로 압축하므로 이를 활용하세요. 긴 페이지는 --slices 3으로 자릅니다.

5. 비평가 모델 선택 (플랫폼이 지원하는 경우에만)

플랫폼에서 하위 에이전트의 모델을 선택할 수 있는 경우에만, 그리고 1라운드 전에 한 번만 질문하세요. 사용자가 이미 지정했다면 건너뛰세요. judge.mjs set critic-model <별칭>으로 답변을 저장하고 매 라운드마다 재사용하세요.

플랫폼질문?방법
Claude Code, Claude 앱예AskUserQuestion, unslop 질문과 동일한 프롬프트에서: Sonnet (균형, 권장), Opus (가장 예리한 시력, 가장 많은 할당량), Haiku (가장 저렴, 미묘한 문제 놓침), 나와 동일
Codex 앱, Codex CLI예채팅에서 질문한 다음, 비평가를 생성할 때 선택 사항 전달
Antigravity아니오생성별 모델 선택권이 없습니다. 비평가는 에이전트 파일 설정에서 실행됩니다. 사용자에게 알리세요.
다른 모든 것아니오하위 에이전트별 모델을 명확히 지원하지 않는 한. 기본값을 사용하고 어떤 모델이 작업을 검토했는지 사용자에게 알리세요.

질문할 때는 절충점을 솔직하게 설명하세요. 약한 비평가는 더 저렴하지만 결함을 더 환각하고 미묘한 것을 놓칩니다. 게이트는 가짜 증거를 잡아냅니다. 나쁜 취향은 잡아낼 수 없습니다.

플랫폼별 정확한 구문: references/platforms.md.

6. 비평가 실행

매 라운드마다 새로운 비평가를 사용하세요. prior.json 이상의 기억이 없고 이전 호출에 대한 이해 관계가 없어야 합니다. bundle이 출력한 메시지를 보내고 다른 것은 보내지 마세요:

당신은 프레임 비평가입니다. 당신의 번들은 <절대 경로>입니다. <절대 경로>/CRITIC.md를 읽고 정확히 따르십시오. 해당 폴더 밖의 것은 열지 마십시오. 검토 JSON만으로 응답하십시오.

  • 아무것도 추가하지 마십시오. 당신이 무엇을 만들었는지 요약, "헤더에 집중", "다리를 수정했습니다" 등. 당신의 의견은 비평가가 절대 받아서는 안 되는 유일한 입력입니다. 사용자가 어떤 것을 확인해 달라고 요청했다면, 그들의 말로 브리프에 이미 있습니다.
  • 포크 금지. 비평가를 포크나 컨텍스트를 상속하는 다른 것으로 실행하지 마십시오. 당신의 전체 대화, 코드를 포함하여 보게 됩니다.
  • 설치된 에이전트 선호. frame-critic이 존재하면 사용하세요. 파일 읽기로 제한되어 있기 때문입니다. 이 스킬이 Claude Code 플러그인으로 제공된 경우 이름은 frame-judge:frame-critic이고, Codex에서는 frame_critic입니다. 그렇지 않으면 동일한 메시지로 범용 하위 에이전트를 사용하세요.
  • Claude Code: 가능하면 샌드박스를 실행하세요. claude CLI가 PATH에 있으면, 하위 에이전트를 생성하는 대신 node <skill>/scripts/critic-sandbox.mjs를 실행하세요. 번들의 개인 복사본에서 별도의 헤드리스 프로세스로 비평가를 실행합니다. 해당 프로세스는 읽기 도구만 있으며, 복사본 외부 읽기를 차단하는 훅이 있고, 스크립트가 검토 자체를 게이트합니다 (7단계 건너뜀). 코드-블라인드가 요청되는 것이 아니라 강제되는 유일한 경로입니다.
  • 다른 모든 곳: 세션 내 하위 에이전트를 사용하고, 코드-블라인드는 비평가의 지침에 의존합니다. Claude Code에서는 7단계의 대화 기록 감사가 엿본 비평가를 여전히 잡아냅니다. Codex, Antigravity 및 Cursor에서는 아무것도 확인하지 않으므로 보고서에 그렇게 명시하세요.

응답을 수정하지 않고 .frame-judge/round-N/review.json에 저장하세요.

7. 게이트

node <skill>/scripts/judge.mjs gate --review .frame-judge/round-N/review.json --reviewer subagent --transcript auto

Claude Code에서 --transcript auto는 비평가 하위 에이전트의 대화 기록을 찾아 게이트가 실제로 연 이미지 수(주장하는 것이 아닌)를 계산하고 번들 외부의 어떤 것도 건드린 경우 검토를 무효화합니다. 다른 곳에서는 플래그를 생략하세요. 적용 범위는 자체 보고되며, 보고서에 그렇게 명시됩니다. (critic-sandbox.mjs는 자체 대화 기록을 자동으로 전달합니다.)

게이트가 결정합니다. 비평가의 기분도, 당신도 아닙니다. 게이트는:

  • 존재하지 않거나 비평가가 열지 않은 아티팩트 ID를 인용하는 문제점, 증거가 없는 문제점, 브리프에 없는 브리프 인용문, 잘못된 심각도 또는 신뢰도 값을 거부합니다.
  • 적용 범위를 확인합니다: 비평가가 모든 이미지를 열었을 때만 패스로 간주합니다. 대화 기록이 있는 경우 거기서 확인하고, 그렇지 않으면 비평가 자신의 opened 목록에서 확인합니다.
  • 격리를 확인합니다: 대화 기록이 있는 경우 번들 외부 읽기는 검토를 무효화합니다 (RERUN_CRITIC).
  • 나머지를 정렬합니다:
    • must-fix (반드시 수정): 차단 또는 주요, 신뢰도 0.6 이상
    • verify (확인): 차단 또는 주요, 신뢰도 0.6 미만. 더 가까이서 다시 캡처하세요. 맹목적으로 수정하지 마십시오.
    • polish (다듬기): 사소함
    • ignored (무시됨): 사소한 지적
  • CRITIC.md와 루브릭이 편집되지 않았는지 확인하여 누구도 심판을 누그러뜨리지 않았는지 확인합니다.
  • 원장을 업데이트하고 하나의 결정을 출력합니다:
결정의미당신의 행동
PASS남은 must-fix 없음, 브리프에서 누락된 것 없음보고 (9단계)
SELF_PASS동일하나, 자체 검토 폴백에서 비롯됨보고, 그리고 독립적이지 않았다고 명시
REVISEmust-fix 항목 존재8단계, 그리고 새 라운드
RETHINK비평가가 접근 방식이 근본적으로 잘못되었다고 말함재구축 전에 사용자에게 알림
STOP_MAX_ROUNDS제한 도달, 여전히 실패무엇이 열려 있는지 보고, 계속할지 묻기
STOP_PLATEAU이 라운드에서 해결된 것이 없음빙글빙글 돌지 않음. 보고, 묻기
RERUN_CRITIC검토를 사용할 수 없음 (JSON 없음, 대부분 가짜 증거), 이미지를 건너뛴 비평가의 패스, 또는 번들 외부를 읽은 비평가동일한 번들로 새 비평가 실행
STOP_CRITIC_UNRELIABLE두 번째 사용 불가능한 검토더 강력한 비평가 모델 또는 폴백 제안

8. 수정

ID별로 must-fix 항목을 처리하세요. 차단 항목부터 먼저. 다음 라운드 전에 모든 항목에 응답하세요:

node <skill>/scripts/judge.mjs respond R1-F2 fixed "contact foot planted for 4 frames"
node <skill>/scripts/judge.mjs respond R1-F4 disputed "gutters are equal on both sides" --evidence crop.png
node <skill>/scripts/judge.mjs respond R1-F6 wont-fix "user asked for this gradient" --quote "purple to blue gradient"
  • **disputed**는 시각적 증거가 필요합니다. 예: 크롭 또는 추가 프레임. 다음 번들과 다음 비평가가 이를 판단합니다. "CSS에 16px이라고 되어 있음"은 증거가 아닙니다. 픽셀이 증거입니다.
  • **wont-fix**는 수정이 위반할 브리프의 있는 그대로의 인용문이 필요합니다.
  • 원인을 수정하세요. 캡처를 수정하지 마십시오. 문제점을 회피하기 위해 캡처를 변경하지 마십시오: 깨진 푸터 자르기, 모바일 뷰포트 제거, 클립 자르기 등.
  • 확인 항목과 비평가의 requests: 해당 지점을 더 가까이서 캡처하세요 (액션과 clip, 더 조밀한 --motion 창) 다음 비평가가 확인하거나 기각할 수 있도록.
  • 비평가가 keep 아래에 나열한 것을 퇴보시키지 마십시오.

관련 스킬