무료 프롬프트
FREE
스킬
캐러셀 PNG 내보내기 스킬 (export-carousel-png) — 슬라이드별 PNG 추출
이온디
2026.07.17
2
0
평점
0.0
리뷰 0개
사용 방법
본문을 복사해 AI 도구에서 실행하세요
-
STEP 1
아래 본문에서 역할, 목적, 입력값, 출력 형식을 확인합니다.
-
STEP 2
ChatGPT, Claude, Gemini, Codex의 대화창이나 프로젝트 지침에 붙여넣습니다.
-
STEP 3
예시 입력값을 내 업무 정보로 바꾼 뒤 실행하고 결과를 검토합니다.
export-carousel-png는 반복 업무를 더 안정적으로 처리하기 위한 AI 에이전트 스킬입니다.
HTML로 만든 인스타그램 4:5 캐러셀을 슬라이드별 PNG로 내보낼 때 사용한다. outputs/instagram-carousel/.../index.html 같은 단일 HTML 파일에서 각 .slide 요소를 Playwright/Chromium으로 렌더링하고, 임시 로컬 정적 서버를 통해 열어 1080x1350 PNG로 캡처한 뒤 exports/png/slide-01.png 형식으로 저장하며, 이미지 로딩·파일 개수·PNG 크기·빈 이미지 여부까지 검증한다.
사용 방법
Codex나 호환되는 AI 에이전트의 스킬 폴더에 아래 SKILL.md 내용을 저장한 뒤, 설명에 포함된 트리거 문장으로 호출하세요.
사용 예:
export-carousel-png 스킬 사용해줘.
이 작업은 export-carousel-png 기준으로 진행해줘.
연관스킬
이 스킬과 함께 쓰면 좋은 관련 스킬입니다.
원본 위치
.codex/skills/export-carousel-png/SKILL.md
SKILL.md
---
name: export-carousel-png
description: HTML로 만든 인스타그램 4:5 캐러셀을 슬라이드별 PNG로 내보낼 때 사용한다. outputs/instagram-carousel/.../index.html 같은 단일 HTML 파일에서 각 .slide 요소를 Playwright/Chromium으로 렌더링하고, 임시 로컬 정적 서버를 통해 열어 1080x1350 PNG로 캡처한 뒤 exports/png/slide-01.png 형식으로 저장하며, 이미지 로딩·파일 개수·PNG 크기·빈 이미지 여부까지 검증한다.
---
# Export Carousel PNG
## 목표
단일 HTML로 만든 인스타그램 캐러셀을 슬라이드별 PNG 파일로 내보낸다.
기본 대상은 `outputs/instagram-carousel/{project-slug}/index.html`처럼 구성된 HTML 캐러셀이다. 각 슬라이드는 `.slide` 요소로 존재한다고 가정한다.
최종 결과물은 HTML 파일이 있는 폴더 아래의 `exports/png/`에 저장한다.
```text
outputs/
instagram-carousel/
{project-slug}/
index.html
assets/
exports/
png/
slide-01.png
slide-02.png
```
## 입력
사용자가 HTML 파일 경로를 주면 그 파일을 기준으로 진행한다.
사용자가 폴더 경로를 주면 아래 순서로 HTML을 찾는다.
1. `{folder}/index.html`
2. `{folder}` 안의 HTML 파일이 1개뿐이면 해당 파일
3. HTML 파일이 없거나 여러 개면 사용자에게 확인
출력 폴더는 기본적으로 HTML 파일이 있는 폴더의 `exports/png/`를 사용한다. 사용자가 출력 폴더를 명시하면 그 경로를 사용한다.
## 절대 규칙
- 원본 HTML 파일을 수정하지 않는다.
- 원본 `assets/` 파일을 수정하거나 이동하지 않는다.
- 전체 페이지 스크린샷을 최종 산출물로 사용하지 않는다.
- 각 `.slide` 요소를 개별 PNG로 캡처한다.
- 파일명은 `slide-01.png`, `slide-02.png`처럼 2자리 번호로 저장한다.
- 기본 PNG 크기는 1080 x 1350 px이다.
- 캡처 전에 이미지와 폰트 로딩을 기다린다.
- 캡처 후 PNG 개수, PNG 크기, 빈 이미지 여부를 확인한다.
- 실패했을 때 성공한 척하지 말고, 어느 단계에서 실패했는지 보고한다.
## 기본 진행 흐름
1. HTML 경로를 확정한다.
2. HTML 파일과 같은 폴더를 정적 서버의 루트로 잡는다.
3. 사용 가능한 포트를 찾아 임시 로컬 정적 서버를 실행한다.
4. Playwright/Chromium으로 `http://127.0.0.1:{port}/{html-file-name}`을 연다.
5. `.slide` 요소 개수를 확인한다.
6. 런타임에서만 export용 CSS를 주입한다.
7. 각 `.slide` 요소를 `exports/png/slide-XX.png`로 캡처한다.
8. PNG 개수, 크기, 빈 이미지 여부를 검증한다.
9. 임시 서버와 브라우저를 정리한다.
10. 결과 경로와 검증 결과를 보고한다.
## Playwright 실행 기준
Playwright가 필요한 작업이므로, 로컬 환경에서 Playwright 사용 가능 여부를 먼저 확인한다.
확인 예:
```bash
node -e "import('playwright').then(() => console.log('ok'))"
```
패키지가 없으면 임의로 설치하지 말고 사용자에게 설치 여부를 확인한다. 프로젝트에 이미 `package.json`이 있고 Playwright가 의존성에 있다면 기존 프로젝트 의존성을 사용한다.
## 로컬 서버 기준
`file://`로 HTML을 직접 열지 않는다. 상대 이미지 경로와 브라우저 보안 정책 문제를 줄이기 위해 HTML 파일이 있는 폴더를 임시 정적 서버로 연다.
서버는 Python 또는 Node 중 현재 환경에서 가장 간단한 방법을 사용한다.
Python 예:
```bash
python3 -m http.server 4173 --bind 127.0.0.1 --directory /path/to/html-folder
```
이미 포트가 사용 중이면 다른 포트를 사용한다. 작업이 끝나면 임시 서버를 종료한다.
## 임시 CSS 보정 기준
원본 HTML은 수정하지 않는다. 대신 Playwright 런타임에서만 캡처 안정화를 위한 CSS를 주입한다.
보정 목적은 브라우저 보기용 반응형 축소가 PNG 크기에 영향을 주지 않게 만드는 것이다.
필수 보정:
```css
html,
body {
margin: 0 !important;
padding: 0 !important;
background: #000 !important;
}
.slide {
width: 1080px !important;
height: 1350px !important;
transform: none !important;
transform-origin: top left !important;
}
```
필요한 경우에만 보정:
```css
.stage {
width: 1080px !important;
height: 1350px !important;
overflow: visible !important;
}
```
주의:
- 텍스트, 색상, 오버레이, 배경 이미지, 콘텐츠 문안은 바꾸지 않는다.
- `.slide`가 아닌 다른 선택자를 캡처 대상으로 임의 변경하지 않는다.
- `.slide`가 없으면 사용자에게 확인한다.
## 권장 임시 실행 코드
아래 코드는 스킬 사용자가 매번 파일로 저장할 필요는 없다. 필요한 경우 임시 Node 스크립트나 `node -e` 형태로 사용한다.
```js
import { chromium } from "playwright";
import fs from "node:fs/promises";
import path from "node:path";
const htmlPath = "/absolute/path/to/index.html";
const htmlDir = path.dirname(htmlPath);
const outputDir = path.join(htmlDir, "exports", "png");
const url = "http://127.0.0.1:4173/" + path.basename(htmlPath);
await fs.mkdir(outputDir, { recursive: true });
const browser = await chromium.launch();
const page = await browser.newPage({
viewport: { width: 1080, height: 1350 },
deviceScaleFactor: 1,
});
await page.goto(url, { waitUntil: "networkidle" });
await page.evaluate(async () => {
if (document.fonts?.ready) {
await document.fonts.ready;
}
const images = Array.from(document.images);
await Promise.all(
images.map((image) => {
if (image.complete) return Promise.resolve();
return new Promise((resolve, reject) => {
image.addEventListener("load", resolve, { once: true });
image.addEventListener("error", reject, { once: true });
});
})
);
});
await page.addStyleTag({
content: `
html,
body {
margin: 0 !important;
padding: 0 !important;
background: #000 !important;
}
.stage {
width: 1080px !important;
height: 1350px !important;
overflow: visible !important;
}
.slide {
width: 1080px !important;
height: 1350px !important;
transform: none !important;
transform-origin: top left !important;
}
`,
});
const slides = await page.locator(".slide").all();
if (slides.length === 0) {
throw new Error("캡처할 .slide 요소가 없습니다.");
}
for (let index = 0; index < slides.length; index += 1) {
const fileName = `slide-${String(index + 1).padStart(2, "0")}.png`;
const outputPath = path.join(outputDir, fileName);
await slides[index].screenshot({
path: outputPath,
animations: "disabled",
caret: "hide",
});
}
await browser.close();
```
## 검증 기준
PNG 생성 후 반드시 검증한다.
필수 검증:
- `exports/png/` 폴더가 존재하는가?
- PNG 개수가 `.slide` 개수와 같은가?
- 파일명이 `slide-01.png`부터 순서대로 존재하는가?
- 각 PNG 크기가 1080 x 1350 px인가?
- 파일 크기가 0 byte가 아닌가?
- 이미지가 완전히 빈 단색 화면으로 보이지 않는가?
macOS에서는 `sips`로 크기를 확인할 수 있다.
```bash
sips -g pixelWidth -g pixelHeight /path/to/exports/png/slide-*.png
```
Node로도 검증할 수 있다. PNG 크기 확인은 `pngjs`, `sharp`, ImageMagick, `sips` 중 현재 환경에서 사용 가능한 도구를 사용한다.
## 실패 대응
PNG 크기가 1080 x 1350이 아니면 1회만 자동 보정 재시도한다.
재시도 시 확인할 것:
- Playwright viewport가 `{ width: 1080, height: 1350 }`인지 확인
- `deviceScaleFactor`가 `1`인지 확인
- `.slide`의 `transform`이 런타임 CSS로 제거됐는지 확인
- `.slide`의 `width`와 `height`가 1080 x 1350으로 계산되는지 확인
- `.stage`가 슬라이드를 자르거나 축소하지 않는지 확인
1회 재시도 후에도 실패하면 더 이상 임의 보정하지 말고 중단한다. 최종 보고에 실제 생성된 파일, 실패한 파일, 실제 크기, 의심 원인을 적는다.
`.slide` 요소가 없으면 캡처 대상을 추측하지 말고 사용자에게 확인한다.
이미지 로딩 실패가 있으면 해당 asset 경로와 브라우저 콘솔 오류를 확인해 보고한다.
## 최종 보고 형식
작업을 마치면 짧게 보고한다.
```text
완료했습니다.
입력 HTML: /absolute/path/to/index.html
출력 폴더: /absolute/path/to/exports/png
생성 PNG: 8장
검증 결과: 8개 모두 1080 x 1350 px, 파일 존재 확인 완료
주의 사항: 없음
```
실패했다면 아래처럼 보고한다.
```text
PNG 내보내기를 완료하지 못했습니다.
입력 HTML: /absolute/path/to/index.html
성공한 파일: slide-01.png ~ slide-04.png
실패 단계: slide-05.png 캡처 후 크기 검증
실제 크기: 864 x 1080 px
의심 원인: .slide transform 보정이 적용되지 않았습니다.
다음 조치: HTML 구조 또는 캡처 대상 선택자를 확인해야 합니다.
```
리뷰
별점과 함께 남기는 사용 후기
아직 리뷰가 없습니다
리뷰를 작성하려면 로그인하세요.
첫 리뷰를 남겨보세요.