3 features:
- Gongnyangi Chart — Consulting-style data chart (960x500 PNG)
- Gongnyangi Card News — Instagram card news in 5 designs (1080x1350 PNG)
- Gongnyangi Video — Remotion animated chart (MP4/GIF)
STEP 0: Preliminary Questions (Must Be Done First)
Before writing code, always ask the user the following. Do not make it right away.
When Requesting a Gongnyangi Chart
1. 어떤 데이터를 차트로 만들까요? (항목명 + 수치)
2. 차트 유형은? (바 차트 / 비교표 / A vs B / 프로세스 / 타임라인)
3. 강조할 항목은? (빨강으로 표시할 것)
4. 제목은? (인사이트 형태 — "매출 추이" X, "Q4 매출 15% 급등" O)
5. 출처(Source)는?
When Requesting Gongnyangi Card News
1. 주제/내용은 무엇인가요? (텍스트 파일 경로 또는 직접 입력)
2. 몇 장짜리로 만들까요? (4장 / 6장 / 9장)
3. 각 장에 들어갈 핵심 메시지는? (제가 제안할까요, 직접 정해주실 건가요?)
4. 디자인 테마는? (editorial / impact / grid / dark-slim / minimal)
- 잘 모르겠으면 제가 주제에 맞는 테마를 추천합니다
5. 레퍼런스 스타일이 있나요? (참고할 카드뉴스 URL이나 계정)
6. 핸들/브랜드명은? (하단에 표시할 @이름)
After asking, submit a plan in text first:
=== 카드뉴스 기획안 ===
테마: impact
장수: 4장
핸들: @gongnangi
[1장 - 커버]
핵심 숫자: 0.25%
제목: 프롬프트 엔지니어링은 끝났다
설명: ...
[2장 - 데이터]
차트 유형: 슬림 바 차트
데이터: 도구출력 80%, 대화기록 5%, ...
인사이트: ...
[3장 - 인용구]
인용: "just the right information..."
저자: Andrej Karpathy
[4장 - 프레임워크]
구조: Write / Select / Compress / Isolate
...
=== 기획안 끝 ===
이대로 만들까요?
Start writing code only after the user approves.
Never Allow Empty Space (Top-Priority Rule)
This rule takes precedence over all other rules.
- Empty space on the canvas must not exceed 20%
- If empty space is visible at the bottom → increase the font size or add content to fill it
- Do not scatter elements with margin:auto, flex:1, justify-content:space-between, etc.
- Stack all elements tightly from top to bottom (gap within 24-32px)
- After rendering, always open the PNG with Read to visually check for empty space
- If empty space is visible, fix it and re-render (automatic, up to 3 times)
When Requesting a Gongnyangi Video
1. 어떤 차트를 영상으로 만들까요? (바 차트 / 카운트업 / 프레임워크 순차등장)
2. 데이터는? (기존 차트 재활용 or 새로 만들기)
3. 사이즈는? (960x500 차트용 / 1080x1350 카드뉴스용 / 1920x1080 가로 와이드)
4. 출력 형식은? (MP4 / GIF / 둘 다)
Post-Render Quality Verification Feedback Loop (Required)
After rendering a PNG, always run the 5-step verification. If even one fails, fix it and re-render (up to 3 times).
Step 1: Clipping Check
# 2배 높이로 렌더하여 하단 잘림 확인
CHROME --screenshot=check.png --window-size=1080,2700 file.html
# check.png 크기가 정상의 1.5배 이상이면 OVERFLOW → FAIL
Step 2: Visual Check (Open PNG with Read)
- Is the text clearly visible (on a dark background, #555 or lower is not visible → #999+)
- If bottom empty space is 20%+ → FAIL
- Is the bar chart in the slim 6px style
- Is there no border box
- Are the mini preview/swatches not so small that they break
Step 3: OCR Readability Test
Open the PNG with Read and check whether all text is legible to the eye:
- If characters are broken or cut off and unreadable → FAIL
- If fonts under 14px are blurry → FAIL
- Text inside mini previews must also be readable → if not readable, enlarge the preview or remove the text
Step 4: Self-Evaluation Checklist
□ 빈 공간이 20% 미만인가?
□ 모든 텍스트가 읽히는가? (깨진 글자 없는가?)
□ 각 요소의 특징이 구별되는가? (같은 내용 반복 아닌가?)
□ 색상 대비가 충분한가? (배경 대비 텍스트 명도차 50%+)
□ 바 차트가 슬림 6px 스타일인가?
□ 박스 테두리(border)가 없는가?
□ 하단에 핸들/출처가 있는가?
□ 잘리는 콘텐츠가 없는가?
Step 5: Automatic Fix on Failure
- OVERFLOW → reduce padding or reduce font-size
- Text not visible → raise the color (#555 → #999)
- Broken characters → increase font-size or remove the element
- Excessive empty space → increase font-size or add descriptions
- Features not distinguishable → apply different content/colors to each item
- After fixing, re-render → re-verify from Step 1 (repeat up to 3 times)
Design Principles
McKinsey/Bain/BCG consulting report standard:
- Color: Default everything grayscale. Accent is red (#c0392b) only.
- Zero decoration: No emoji. No icons. No gradients. No rounded corners. No shadows.
- Typography: Title = insight (not description). Numbers large, labels small. Noto Sans KR.
- Structure: Lines thin and precise. Whitespace intentional. Every pixel carries data.
- Source: Always include
Source:line at the bottom. - Action Title: Title must pass "So What?" test. Quantify where possible.
- Philosophy: "Everything loud means nothing stands out. One thing catches the eye."
Design Tokens
{
"color": {
"title": "#111", "body": "#222", "cell": "#333",
"secondary": "#555", "label": "#888", "subtitle": "#999",
"source": "#bbb", "connector": "#ccc", "bar-default": "#d5d5d5",
"divider": "#eee", "bar-bg": "#f5f5f5", "cell-bg": "#fafafa",
"warning-bg": "#fdf5f5", "accent": "#c0392b"
},
"typography": {
"chart": { "title": "22px/700", "sub": "11px/400", "source": "9px/300" },
"cardnews": {
"hero": "72px/700", "title": "48px/700", "heading": "36px/700",
"subhead": "28px/400", "body": "24px/400", "label": "18px/400",
"caption": "14px/300", "source": "12px/300"
}
},
"layout": {
"chart": "960x500",
"cardnews": "1080x1350"
}
}
Base CSS (Chart Mode — 960px)
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300;400;700&display=swap');
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'Noto Sans KR',sans-serif;background:#fff;padding:28px 36px 20px;width:960px;color:#222}
.title{font-size:22px;font-weight:700;color:#111;margin-bottom:2px}
.sub{font-size:11px;color:#999;margin-bottom:24px}
.source{font-size:9px;color:#bbb;margin-top:18px}
Base CSS (Card News Mode — 1080x1350)
body{width:1080px;height:1350px;padding:80px 72px 60px;display:flex;flex-direction:column}
.slide-num{font-size:14px;color:#ccc;margin-bottom:40px}
.title{font-size:40px;font-weight:700;color:#111;line-height:1.3;margin-bottom:40px}
.body{font-size:24px;color:#555;line-height:1.7}
.highlight{color:#c0392b;font-weight:700}
.bottom{font-size:12px;color:#ccc;margin-top:auto}
Chart Types
1. Horizontal Bar Chart
- Default bar:
background:#d5d5d5, Highlight:background:#c0392b - Labels left-aligned, values right. Bar height 18-22px, background #f5f5f5
2. Comparison Table
- Header: 10px, #999, bottom 2px solid #111
- Cell: 11px, #333, bottom 1px solid #eee. Highlight: color:#c0392b
3. Side-by-Side (A vs B)
display:flex;gap:1px;background:#eee— 1px divider- Highlight side title in #c0392b
4. Process / Flow
- Numbers: 28-32px, bold, #d5d5d5 (highlight: #c0392b). Arrows:
→, color:#ccc
5. Timeline
- Horizontal axis: height:2px, background:#222. Nodes: 14px circles. Current: #c0392b
6. Level / Severity
- Color bar tags + description. Scale: #c0392b → #e67e22 → #555 → #999
Card News — 5 Design Themes
Instagram 4:5 portrait (1080x1350). When the user selects a design, generate the full set in that style.
Select design
| # | Theme | Background | Accent | Layout | Feel |
|---|---|---|---|---|---|
| 1 | editorial | #FAFAFA light | #FF4444 | Left-aligned asymmetric | Magazine |
| 2 | impact | #0A0A0A dark | #c0392b | Center-aligned | Dramatic impact |
| 3 | grid | #F0EBE3 + #2C2C2C | #8B6F4E | Left-right 2-column split | Structural |
| 4 | dark-slim | #0A0A0A dark | #c0392b | Left-aligned | Slim chart |
| 5 | minimal | #F5F5F5 light | #c0392b | Center-aligned | Black-and-white minimal |
Default: impact (when no design is specified)
Common typography rules
핵심 숫자: 160-200px, weight 900, letter-spacing -6px
제목 핵심: 48-56px, weight 900
제목 연결어: 같은 크기, weight 100-300 (대비)
본문: 22-28px, weight 300-500, line-height * 1.618
라벨: 11-13px, letter-spacing 3-5px, uppercase
- Different size/weight/color for each line (no 3 consecutive lines in the same style)
- Content occupies 70%+ of the canvas
- padding: top 100px, left/right 72px, bottom 72px
- safe zone: top/bottom 135px (prevents cropping in the Instagram grid)
- Bottom: series name on the left + @handle on the right
Common bar chart rules (slim style)
.bar-track{height:6px;background:#f5f5f5} /* 라이트 */
.bar-track{height:6px;background:#1A1A1A} /* 다크 */
.bar-accent{background:#c0392b}
.bar-mid{background:#888}
.bar-light{background:#CCC}
Slide structure (SCQA + Pyramid)
| Slide | Role | Content |
|---|---|---|
| cover | Hook | Key number + title + description |
| data | Complication | Slim bar chart + "why it's a limitation" explanation |
| quote | Pivot | Key quote, contrast in weight/color per line |
| framework | Evidence | Framework/axes, number + name + description hierarchy |
Prohibitions
- No border-radius, box-shadow
- No making boxes with border (only border-top/bottom dividers allowed)
- No distributing empty space with margin:auto
- No 3 consecutive lines of text in the same style
Animation System (Remotion)
Spring physics-based animation with React + Remotion → render to MP4/GIF.
In WSL, LD_LIBRARY_PATH setup required (install.sh guides automatically).
Remotion composition list
Chart animation (960x500)
| ID | Description | Animation |
|---|---|---|
| BarChart | Horizontal bar chart | Bars rise from 0 with spring |
| CountUp | Number count-up | 0→target number spring deceleration |
| FourAxis | 4-axis framework | Axes slide in one by one |
| CompareAB | A vs B two-way comparison | Both bars grow simultaneously |
| ProcessFlow | Process flow | Steps appear in order + arrows |
| QuoteReveal | Quote | Each line appears with different weight/color |
| TableReveal | Table | Rows slide in in order |
| NumberPulse | Number emphasis | Large number pops in + repeated pulse |
| Timeline | Timeline | Draw axis + nodes appear in order |
Card news videoization (1080x1350 / 1920x1080)
| ID | Description | Animation |
|---|---|---|
| CardCover | Cover slide | Number pop → title slide-in → description fade |
| CardData | Data slide | Title → bar sequential growth → insight appearance |
| BarChart-Card | Bar chart (card news size) | 1080x1350 version of BarChart |
| CardCover-Wide | Cover (wide) | 1920x1080 horizontal format |
| CardData-Wide | Data (wide) | 1920x1080 horizontal format |
Showreel (1920x1080)
| ID | Description |
|---|---|
| SkillIntro | Skill introduction (3 in 1) |
| Showreel | Full compilation (Intro→Chart→CardNews→Outro) |
Animation Patterns
/* Bar grow */
@keyframes barGrow{from{width:0}to{width:var(--target)}}
.bar{animation:barGrow 0.8s cubic-bezier(0.25,0.46,0.45,0.94) forwards}
/* Fade in with slide up */
@keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
/* Scale in (for numbers) */
@keyframes scaleIn{from{transform:scale(0.5)}to{transform:scale(1)}}
Stagger Timing
- Title: 0s
- Subtitle: 0.2s
- Data rows: 0.4s + (index * 0.2s)
- Source line: last animation + 0.5s
- Hold final frame: +1 second
Capture Pipeline (PowerShell + Windows Chrome)
# Frame capture with virtual time
& $chrome --headless=new --disable-gpu --hide-scrollbars `
--screenshot="$outFile" `
--window-size=960,500 `
--virtual-time-budget=$timeMs `
"file:///$htmlPath"
Encode Pipeline (ffmpeg)
FFMPEG="path/to/ffmpeg.exe"
# GIF (high quality with palette optimization)
"$FFMPEG" -y -r 15 -i "frames/frame-%04d.png" \
-vf "fps=15,scale=960:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" \
output.gif
# MP4 (H.264)
"$FFMPEG" -y -r 15 -i "frames/frame-%04d.png" \
-c:v libx264 -pix_fmt yuv420p -crf 18 \
output.mp4
# APNG (animated PNG, infinite loop)
"$FFMPEG" -y -r 15 -i "frames/frame-%04d.png" \
-plays 0 output.apng
PNG Export (Static)
CHROME="/mnt/c/Program Files/Google/Chrome/Application/chrome.exe"
# Chart (960x500)
"$CHROME" --headless=new --disable-gpu --hide-scrollbars \
--screenshot="D:\\output\\chart.png" \
--window-size=960,500 \
"file:///D:/input/chart.html"
# Card News (1080x1350)
"$CHROME" --headless=new --disable-gpu --hide-scrollbars \
--screenshot="D:\\output\\card.png" \
--window-size=1080,1350 \
"file:///D:/input/card.html"
Prohibited
- Emoji
- Gradients (linear-gradient)
- border-radius (except tables)
- box-shadow
- More than 1 background color on badges/tags
- Any "decorative" element — if it's not data, it doesn't belong
- Description titles ("sales trend") — always action titles ("Q4 sales surged 15%")