Communitygithub.com

ethanweber/posterskill

논문과 프로젝트 웹사이트로부터 HTML 컨퍼런스 포스터를 생성하고 PDF로 인쇄합니다.

posterskill란 무엇인가요?

이 스킬은 논문(Overleaf 소스)과 프로젝트 웹사이트를 기반으로 전문적인 HTML 컨퍼런스 포스터를 생성합니다. React 기반의 대화형 편집기를 포함한 단일 HTML 파일을 생성하며, 별도의 빌드 과정 없이 CDN을 통해 React를 로드합니다. 사용자는 브라우저에서 레이아웃을 시각적으로 조정하고, 구성(config)을 다시 클로드에게 내보내어 추가 변경을 요청할 수 있습니다. 이 스킬은 Playwright를 사용하여 레이아웃의 여백을 최적화하고, 참조 포스터의 스타일을 분석하여 일관된 디자인을 유지합니다. 최종적으로 포스터를 PDF로 생성하여 검증한 후, 사용자가 원하는 경우 GitHub 저장소에 푸시할 수 있습니다. 주요 특징으로는 이미지 종횡비에 따른 칼럼 할당을 통한 여백 최소화, KaTeX 수식 지원, A-/A+ 버튼을 통한 전역 폰트 크기 조절, 드래그 기반 카드 재배치 등이 있습니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ethanweber/posterskill/tree/HEAD/.claude/skills/make-poster

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

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

미리보기

스킬 README에서

posterskill preview

문서

컨퍼런스 포스터 생성기 (HTML)

전문 HTML 포스터를 생성합니다. 사용자 참고: $ARGUMENTS

포스터는 React 기반 대화형 편집기입니다. poster/ 디렉토리 안에 있는 단일 자체 포함 HTML 파일입니다. 빌드 단계가 필요 없습니다(React/Babel이 CDN을 통해 로드됨). 사용자는 브라우저에서 레이아웃을 시각적으로 조정한 후 구성을 클로드로 내보내 추가 변경을 요청할 수 있습니다.

프로젝트 폴더 구조

<project>/
├── overleaf/              # Overleaf에서 가져온 논문 소스
│   ├── paper.tex
│   ├── figures/
│   └── ...
├── references/            # 스타일 매칭을 위한 참조 포스터
│   └── (모든 형식: pdf, png, jpg, html, pptx, ...)
├── poster/                # 생성됨: 자체 포함 포스터 웹사이트
│   ├── index.html         # 포스터 (React 앱)
│   ├── poster-config.json # 레이아웃 구성 (칼럼, 카드 순서, 높이, 글꼴 배율)
│   ├── logos/             # 기관 로고
│   ├── teaser.png         # 복사/변환된 그림
│   ├── qr.png             # 프로젝트 페이지 QR 코드
│   ├── qr-posterskill.png # Posterskill QR 코드
│   └── ...
└── .claude/skills/make-poster/
  • overleaf/ 에는 논문 소스가 들어 있습니다. 주요 .tex 파일과 해당 파일이 \input{}하는 모든 파일을 읽으십시오.
  • references/ 에는 사용자가 선호하는 시각적 스타일을 보여주는 예제 포스터가 포함되어 있습니다. 이 폴더의 모든 파일을 읽고/보고 디자인 언어를 일치시키십시오.
  • poster/ 는 생성된 출력물(자체 포함 웹사이트)입니다. 모든 그림과 에셋이 index.html과 함께 있으므로 상대 경로가 바로 작동합니다.

입력

  1. 논문 소스 - overleaf/에 있습니다. 사용자에게 읽을 주요 .tex 파일(예: paper.tex, main.tex)을 물어보십시오. 그런 다음 해당 파일과 \input{}하는 모든 파일을 읽으십시오.
  2. 프로젝트 웹사이트 - 아직 알려지지 않은 경우 사용자에게 URL을 물어보십시오. WebFetch로 가져와 저자 정보, 호스팅된 이미지 및 링크를 추출하십시오.
  3. 참조 포스터 - references/에서 자동으로 발견됩니다. 해당 폴더의 모든 파일을 보고 스타일을 일치시키십시오.
  4. 저자 웹사이트 (선택 사항) - WebFetch로 가져와 디자인 신호(색상 팔레트, 타이포그래피, 로고)를 추출하십시오. 저자 사이트에서 기관 로고를 Playwright를 사용하여 다운로드하십시오(curl은 리디렉션으로 인해 실패할 수 있음): page.request.get(url)로 원시 바이트를 다운로드하십시오.
  5. 서식 요구 사항 - 포스터 치수, 방향, 칼럼 수를 물어보십시오.
  6. Git 저장소 (선택 사항) - 사용자에게 포스터를 푸시할 GitHub 저장소가 있는지 물어보십시오.

사용자가 서식을 지정하지 않은 경우, 진행하기 전에 물어보십시오. 치수, 방향 또는 칼럼 수에 대한 기본값을 가정하지 마십시오.

프로세스

0단계: 스타일 참조 분석

references/에서 PDF, PNG 또는 이미지 파일을 찾으십시오. PDF를 PNG로 변환하십시오(sips -s format png on macOS). 각각을 보고 시각적 스타일(레이아웃, 색상, 타이포그래피, 카드 스타일, 그림 배치)을 기록하십시오. 참조 스타일을 일치시키십시오 — 참조가 밝은 경우 어두운 테마를 기본값으로 사용하지 마십시오.

1단계: 논문 소스에서 콘텐츠 추출

사용자에게 읽을 .tex 파일을 물어보십시오. 추출: 제목, 저자, 소속, 초록(2-3문장), 핵심 방법, 결과(표 + 그림), 핵심 방정식(최대 1-2개), 결론.

2단계: 프로젝트 웹사이트 가져오기

WebFetch를 사용하여 저자 이름, 소속, 그림 URL, QR용 프로젝트 URL, 코드/arxiv/비디오 링크를 가져오십시오.

3단계: 에셋을 poster/로 수집

그림: overleaf/figures/에서 복사하고 PDF를 고해상도 PNG로 변환하십시오:

sips -s format png input.pdf --out poster/output.png -Z 3000

웹사이트 이미지: Playwright를 사용하여 프로젝트 웹사이트에서 더 높은 품질의 이미지를 다운로드하십시오(curl이 아닙니다 — 많은 사이트가 리디렉션함):

resp = page.request.get(url)
with open('poster/filename.png', 'wb') as f:
    f.write(resp.body())

로고: Playwright를 사용하여 저자의 개인 웹사이트에서 기관 로고를 다운로드하십시오. poster/logos/에 저장하십시오. 템플릿이 헤더를 위해 자동으로 로고를 흰색으로 반전시킵니다.

QR 코드: 생성 및 저장:

curl -sL -o poster/qr.png "https://api.qrserver.com/v1/create-qr-code/?size=400x400&data=PROJECT_URL"
curl -sL -o poster/qr-posterskill.png "https://api.qrserver.com/v1/create-qr-code/?size=400x400&data=https://github.com/ethanweber/posterskill"

4단계: 이미지 종횡비 측정

여백 제거에 매우 중요합니다. 모든 이미지를 측정하십시오:

sips -g pixelWidth -g pixelHeight poster/*.png poster/*.jpg

그런 다음 종횡비에 따라 이미지를 칼럼에 할당하십시오:

  • 넓은 이미지(>2:1 비율, 예: 티저, 아키텍처): 가장 넓은 칼럼에 배치
  • 정사각형 이미지(~1:1 비율): 좁은 칼럼에 배치
  • 세로 이미지(<1:1 비율): 가장 좁은 칼럼에 배치

이렇게 하면 #1 여백 문제(넓은 이미지가 좁은 셀에 있거나 그 반대의 경우)를 방지할 수 있습니다.

5단계: 포스터 HTML 생성

${{CLAUDE_SKILL_DIR}}/template.html을 시작점으로 사용하십시오. 템플릿은 다음과 같은 React 앱입니다:

아키텍처:

  • CARD_REGISTRY — 각 카드의 콘텐츠(제목, 색상, JSX 본문)를 정의
  • DEFAULT_LAYOUT — 칼럼 구조와 카드 순서를 정의
  • DEFAULT_LOGOS — 헤더용 기관 로고
  • React 상태가 레이아웃을 관리하며, localStorage로 지속성 제공
  • window.posterAPI는 프로그래밍 방식 제어를 위한 함수 노출

사용자 정의해야 할 주요 항목:

  1. 논문 콘텐츠로 CARD_REGISTRY 업데이트(각 섹션은 카드)
  2. 종횡비 최적화 칼럼 할당으로 DEFAULT_LAYOUT 업데이트
  3. 사용자의 기관 로고로 DEFAULT_LOGOS 업데이트
  4. DEFAULT_FONT_SCALE 업데이트(1.3에서 시작, 사용자가 A-/A+ 버튼으로 조정 가능)
  5. 헤더 업데이트(제목, 저자, 소속, 컨퍼런스 배지, QR 코드)
  6. 포스터 치수에 맞게 @page { size: WIDTHmm HEIGHTmm; } 및 body { width: WIDTHmm; height: HEIGHTmm; } 업데이트
  7. 동일한 치수로 posterAPI fit() 함수 업데이트

카드 콘텐츠 패턴:

  • 그림 카드: <div className="fig"><div className="fig-wrap"><img src="file.png" alt="..." /></div><div className="cap"><b>캡션 제목.</b> 설명.</div></div>
  • 텍스트 카드: <div className="hl"><p>강조 텍스트</p></div><ul><li>포인트 1</li></ul>
  • 표 카드: <table><thead>...</thead><tbody>...</tbody></table> (우승 셀에 className="best" 사용)
  • 방정식 카드: <div className="eq">{'$LaTeX 방정식$'}</div> (JSX에서 백슬래시 이스케이프)

여백 제로를 위한 중요한 CSS 규칙:

  • 이미지는 반드시 width:100%; height:100%; object-fit:contain을 사용해야 합니다(max-width/max-height가 아님 — 확장을 방지함)
  • 각 칼럼은 항상 하나의 grow: true 카드(flex:1)를 가져야 하며, 이 카드가 남은 공간을 채웁니다
  • isCardGrow() 함수는 이를 자동으로 보장합니다 — grow 카드가 없으면 마지막 카드가 grow를 받습니다

뷰포트 스케일링:

  • translate() + scale()을 body에 사용하여 포스터를 모든 브라우저 뷰포트에 중앙 정렬 및 맞춤
  • transform-origin: top left가 중요합니다
  • @media print는 올바른 인쇄 해상도를 위해 transform: none !important를 설정해야 합니다
  • getBoundingClientRect()는 스케일링된 값을 반환합니다 — 크기 조정 핸들러에서 항상 currentScaleRef.current로 나누어야 합니다

6단계: Playwright로 레이아웃 자동 최적화

생성 후 Playwright를 사용하여 여백을 측정하고 최적의 칼럼 너비를 찾으십시오:

from playwright.sync_api import sync_playwright
import os

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page(viewport={'width': 3200, 'height': 2260})
    page.goto('file://' + os.path.abspath('poster/index.html'))
    page.wait_for_load_state('networkidle')
    page.wait_for_timeout(3000)

    # 여백 측정
    waste = page.evaluate('window.posterAPI.getWaste()')
    print(f"총 여백: {waste['total']}px")
    for d in waste['details']:
        print(f"  {d['card']}: H={d['wasteH']} W={d['wasteW']} ({d['pct']}%)")

    # 여백을 최소화하기 위해 다른 칼럼 너비 시도
    best_waste = waste['total']
    best_c1, best_c3 = 300, 230
    for c1 in range(200, 350, 10):
        for c3 in range(160, 280, 10):
            page.evaluate(f'window.posterAPI.setColumnWidth("col1", {c1})')
            page.evaluate(f'window.posterAPI.setColumnWidth("col3", {c3})')
            page.wait_for_timeout(30)
            w = page.evaluate('window.posterAPI.getWaste().total')
            if w < best_waste:
                best_waste = w
                best_c1, best_c3 = c1, c3

    # 최적값 적용 및 스크린샷
    page.evaluate(f'window.posterAPI.setColumnWidth("col1", {best_c1})')
    page.evaluate(f'window.posterAPI.setColumnWidth("col3", {best_c3})')
    page.wait_for_timeout(500)
    page.screenshot(path='/tmp/poster_screenshot.png')

    # 칼럼 간 카드 교체도 시도
    page.evaluate('window.posterAPI.swapCards("cardA", "cardB")')
    # ... 여백 다시 측정 ...

    browser.close()

그런 다음 /tmp/poster_screenshot.png를 읽어 시각적으로 검사하십시오. 여러 번 반복하십시오 — 스크린샷을 찍고, 문제를 수정하고, 포스터에 최소한의 빈 공간이 생길 때까지 다시 스크린샷을 찍으십시오.

최적값을 찾은 후에는 이를 HTML의 DEFAULT_LAYOUT, DEFAULT_CARD_HEIGHTS 등에 포함시키십시오.

7단계: PDF 생성 및 확인

page.pdf(
    path='poster/poster.pdf',
    width='841mm', height='594mm',  # 포스터 치수와 일치
    margin={'top':'0','right':'0','bottom':'0','left':'0'},
    print_background=True
)

PDF를 PNG로 변환하고 읽어 전체 해상도로 렌더링되는지 확인하십시오:

sips -s format png poster/poster.pdf --out /tmp/poster_pdf_check.png -Z 3000

8단계: 사용자와 함께 열고 반복

브라우저에서 포스터를 여십시오:

open poster/index.html

사용자에게 편집 컨트롤을 설명하십시오:

  • 미리보기 — 편집 UI를 꺼서 인쇄될 모습을 정확히 봄
  • A-/A+ — 글꼴 크기를 전역적으로 조정
  • 칼럼 구분선 드래그(세로 파란색 막대) — 칼럼을 왼쪽/오른쪽으로 크기 조정
  • 행 구분선 드래그(가로 파란색 막대) — 칼럼 내에서 카드를 위/아래로 크기 조정
  • 클릭하여 교체 — 한 카드의 다이아몬드 핸들(주황색으로 변함)을 클릭한 다음 다른 카드를 클릭하여 교체
  • 이동/삽입 — 카드 핸들을 클릭한 다음 점선 주황색 드롭 영역을 클릭하여 그곳으로 이동
  • 저장 — poster-config.json 다운로드
  • 구성 복사 — 레이아웃 JSON을 클립보드에 복사
  • 초기화 — 기본값 복원

적극적으로 개선 사항 제안: 첫 번째 초안을 보여준 후, 구체적인 변경을 제안하십시오:

  • "모델 아키텍처 카드에 여백이 있습니다 — 위의 행 구분선을 아래로 드래그하여 공간을 줄여보세요"
  • "완료 그림은 더 넓으므로 칼럼 2에 있으면 더 좋을 수 있습니다 — 다이아몬드를 클릭한 다음 칼럼 2의 드롭 영역을 클릭해보세요"
  • "A+를 몇 번 눌러 글꼴 크기를 키우는 것이 좋을 수도 있습니다"

피드백 루프를 장려하십시오: 사용자에게 알리십시오:

브라우저에서 포스터를 재배열해보세요! 레이아웃이 마음에 들면 오른쪽 상단 도구 모음에서 구성 복사를 클릭하고 여기에 붙여넣으십시오 — 그 변경 사항을 기본값에 반영하여 유지하겠습니다.

사용자가 구성 JSON을 붙여넣으면 HTML의 DEFAULT_LAYOUT, DEFAULT_CARD_HEIGHTS, DEFAULT_FONT_SCALE 및 DEFAULT_LOGOS를 일치하도록 업데이트하십시오. 또한 poster-config.json에 기록하십시오.

9단계: GitHub에 푸시(선택 사항)

사용자가 GitHub 저장소 URL을 제공하는 경우:

cd poster
git init
git remote add origin <REPO_URL>
git add .
git commit -m "포스터: <논문 제목>"
git push -u origin main

중요 지침

  • 빈 공간 없음. 이것이 최우선 순위입니다. 종횡비를 인식한 칼럼 할당, 이미지에 width:100%; height:100%; object-fit:contain, 자동 증가 카드, Playwright 최적화 프로그램을 사용하십시오. 여백이 최소화될 때까지 반복하십시오.
  • 텍스트를 최소화하십시오. 포스터는 시각적입니다 — 문단이 아닌 글머리 기호입니다. 2분 이해.
  • 참조 스타일을 일치시키십시오. 참조 포스터가 밝고 깔끔하면 어두운 테마를 사용하지 마십시오. 전체적인 미적 감각을 일치시키십시오.
  • 글꼴 스케일링. 모든 텍스트 크기는 calc(Xpt * var(--font-scale))를 사용하므로 A-/A+ 버튼이 작동합니다. --font-scale: 1.3으로 시작하고 사용자가 조정하도록 하십시오.
  • 인쇄 최적화 CSS. @media print는 모든 편집 UI를 숨기고 transform: none !important를 설정합니다. @page는 정확한 치수를 설정합니다.
  • Posterskill QR. 항상 헤더에 "내 Claude 스킬로 만든 포스터"라는 레이블과 함께 https://github.com/ethanweber/posterskill에 연결되는 QR 코드를 포함하십시오.
  • 감사 페이지 없음. 포스터를 깔끔하게 유지하십시오 — 기본적으로 바닥글 없음.
  • 헤더의 로고. 저자 웹사이트에서 기관 로고를 다운로드하여 poster/logos/에 저장하고 DEFAULT_LOGOS에 나열하십시오. CSS 필터를 통해 자동으로 흰색으로 반전됩니다.
  • 자체 포함. 빌드 단계, npm, 서버가 필요 없습니다. CDN 종속성이 있는 단일 HTML 파일입니다. file://로 직접 열 때 작동합니다.
  • 방정식. KaTeX를 사용하십시오(CDN을 통해 로드). JSX 문자열에서 백슬래시를 이스케이프하십시오: {'$\mathcal{E}$'}.

그림 처리

  • 필요한 그림은 항상 poster/로 복사하십시오 — HTML에서 overleaf/ 경로를 참조하지 마십시오.
  • PDF를 고해상도 PNG로 변환: sips -s format png input.pdf --out poster/output.png -Z 3000
  • Playwright의 page.request.get()을 통해 웹사이트 이미지를 다운로드하십시오(curl이 아님 — 웹사이트는 종종 리디렉션합니다).
  • sips -g pixelWidth -g pixelHeight로 종횡비를 측정하고 그에 따라 칼럼에 할당하십시오.

구성 업데이트를 위한 사용자 워크플로우

사용자는 브라우저에서 포스터를 조정하고 변경 사항을 다시 공유할 수 있습니다:

  1. 사용자가 도구 모음에서 "구성 복사"를 클릭합니다
  2. 사용자가 JSON을 채팅에 붙여넣습니다
  3. Claude가 DEFAULT_LAYOUT, DEFAULT_CARD_HEIGHTS, DEFAULT_FONT_SCALE, DEFAULT_LOGOS를 index.html에서 일치하도록 업데이트합니다
  4. Claude도 구성을 poster-config.json에 기록합니다
  5. 사용자가 새로 고치고 "초기화"를 클릭하여 새 기본값을 로드합니다

프로그래밍 방식 API (window.posterAPI)

브라우저 콘솔 또는 Playwright를 통해 사용 가능:

  • swapCards(id1, id2) — 두 카드 교체(칼럼 간 작동)
  • moveCard(cardId, targetColId, position) — 카드를 특정 위치로 이동
  • setColumnWidth(colId, widthMm) — 칼럼 너비 설정(null은 flex)
  • ...

[번역을 위해 잘림]

관련 스킬