
Info Card Designer
- 152 installs
- 264 repo stars
- Updated April 5, 2026
- joeseesun/info-card-designer
Design polished info cards for social posts, docs, or landing snippets with consistent typography, layout, and visual hierarchy.
About
info-card-designer produces structured, attractive information cards—balancing headline, body, icons, and color so explainers, announcements, and social snippets look professional without a full design toolchain.
- Card layout templates
- Typography hierarchy
- Brand-consistent visuals
- Social and doc-ready output
- Rapid visual iteration
Info Card Designer by the numbers
- 152 all-time installs (skills.sh)
- Ranked #1,011 of 1,880 Design & UI/UX skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/joeseesun/info-card-designer --skill info-card-designerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 152 |
|---|---|
| repo stars | ★ 264 |
| Last updated | April 5, 2026 |
| Repository | joeseesun/info-card-designer ↗ |
What it does
Design polished info cards for social posts, docs, or landing snippets with consistent typography, layout, and visual hierarchy.
Files
Info Card Designer
将任意内容转化为杂志质感信息卡,自动截图 + 超长分割,适配 X/Twitter、小红书分享。
工作流
Step 1:分析内容密度
- 低密度(1 个核心观点)→ 大字符主义布局
- 中密度(2-4 要点)→ 标准单栏布局
- 高密度(5+ 要点)→ 多栏网格布局
Step 2:生成 HTML
读取 references/design-spec.md 获取完整规范。
硬性约束:
- 卡片宽度:默认 600px,可指定 480 / 600 / 900(用户说"480宽"/"900宽"时生效)
<meta name="viewport" content="width=[指定宽度]">防缩放- 背景色
#f5f3ed - 截图时
resize_pagewidth 设为指定宽度
字号用 vw 单位,随宽度自动缩放:
- 主标题:
font-size: clamp(40px, 13vw, 130px)— 480px→62px / 600px→78px / 900px→117px - 条目标题:
font-size: clamp(16px, 4vw, 40px)— 480px→19px / 600px→24px / 900px→36px - 正文:
font-size: clamp(14px, 3.2vw, 24px)— 480px→15px / 600px→19px / 900px→28px - 辅助/标签:
font-size: clamp(11px, 2.2vw, 16px)
内容原则(强制):
- 卡片内容必须 100% 来自用户提供的原文/URL/文本,严禁自行编造或使用占位符
- 标题、描述、来源、金句均须与原文一致,Hook 改写只改表达方式,不改事实
描述风格(Hook 模式,默认开启):
- 每条描述改写为 10-20 字的钩子句,有信息量 + 有冲击感
- 保留核心事实,用主动语态,让读者想点进去看
- 用户说"保持原文"或"不改描述"时关闭
保存路径:/tmp/info-card-[关键词].html
Step 3:截图(必须执行)
优先用 Chrome DevTools MCP,按卡片宽度选择对应 devicePixelRatio(确保输出 PNG 落在 1200-1800px 甜区):
| 卡片宽度 | devicePixelRatio | 输出 PNG 宽度 |
|---|---|---|
| 480px | 3x | 1440px |
| 600px | 2x | 1200px |
| 900px | 2x | 1800px |
1. navigate_page → file:///tmp/info-card-xxx.html 2. emulate → viewport=[宽度]x900x[倍率](e.g. 480px 卡片用 480x900x3,600px 用 600x900x2) 3. resize_page → width=[宽度], height=900 4. take_screenshot → fullPage=true, filePath=[初始路径]
为什么不统一 3x:900px × 3x = 2700px,文件过大且社交平台会压缩,收益递减;480px 因 CSS 宽度小,3x 才能保证 1440px 输出不虚糊。
Step 4:超长分割
截图后检查图片高度。若高度 > 1200px,执行分割:
python3 ~/.claude/skills/info-card-designer/scripts/split_card.py [图片路径] 1200分割后输出 card-1.png, card-2.png ... 等文件。
Step 5:整理并输出
保存路径规则:
~/乔木新知识库/60-69 素材/65 附件库/info-cards/
└── [YYYYMMDD]-[来源]-[主题关键词]/
├── card.png # 未分割时
├── card-1.png # 分割时
└── card-2.png示例:info-cards/20260316-wisereads-134/card-1.png
文件夹名格式:日期-来源-主题,一目了然告知用户:图片路径 + 共几张
---
设计速查
完整规范见 references/design-spec.md。
| 场景 | 布局 | 主标题字号 | 正文字号 |
|---|---|---|---|
| 低密度 | 大字符主义 | 72-120px | 20px |
| 中密度 | 标准单栏 | 48-56px | 18px |
| 高密度 | 2-3 栏网格 | 36-44px | 16px |
字体:标题 Noto Serif SC;正文 Inter / Noto Sans SC
配色:靛蓝 #1a3a6b(知识)/ 深红 #c0392b(警示)/ 墨绿 #1a4a3a(生活)/ 深金 #8b6914(财经)
MIT License
Copyright (c) 2026 joeseesun
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
info-card-designer
Turn any text or URL into a magazine-quality info card image — auto screenshot included.
将任意文本或链接一键转化为杂志质感信息卡片,自动截图输出图片,适合分享到 X、小红书、微信。
[English](#english) | [中文](#中文)
---
<a name="english"></a>
English
What it does
Give Claude a URL, paste text, or describe a topic — this skill designs a magazine-style HTML info card and automatically screenshots it to PNG ready to post on X (Twitter), Xiaohongshu, or WeChat.
Key features:
- Swiss International Style + editorial magazine aesthetic
- Big titles, punchy hook-style summaries (10–20 chars each)
- Supports 480 / 600 / 900px width — just say "make it 480px wide"
- Auto-splits cards taller than 1200px into multiple images
- vw-based font sizing: fonts scale proportionally with card width
Prerequisites
- [ ] Chrome DevTools MCP installed and connected (used for headless screenshot)
- Install: add
chrome-devtoolsMCP server to your Claude Code config - Verify: Claude can call
navigate_page,take_screenshot - [ ] Python 3 with Pillow (for image splitting)
- Install:
pip3 install Pillow - Verify:
python3 -c "from PIL import Image; print('ok')"
Installation
npx skills add joeseesun/info-card-designerHow to trigger
Say any of these to Claude:
- "生成信息卡" / "做张信息卡" / "信息卡片"
- "把这段内容做成卡片"
- "make info card" / "generate card"
Usage examples
用户: 把这个链接做成信息卡 https://wise.readwise.io/issues/wisereads-vol-134/
用户: 把这段内容做成 480 宽的信息卡
用户: generate a card from this text, keep the original descriptionsWidth options
| Width | Best for |
|---|---|
| 480px | Mobile-first, compact |
| 600px | Default, balanced (recommended) |
| 900px | Desktop / large-screen sharing |
Troubleshooting
| Problem | Solution |
|---|---|
| Screenshot fails / page not found | Make sure Chrome DevTools MCP is connected and Chrome is running |
No module named PIL | Run pip3 install Pillow |
| Card content is wrong / made up | The skill is instructed to use only your source content — re-trigger with the URL or paste the text directly |
| Card too tall (1 image) | Splitting is automatic when height > 1200px; check that Pillow is installed |
Credits
Design inspiration from @shao__meng's original post on X: https://x.com/shao__meng/status/2027368489439334504
---
<a name="中文"></a>
中文
功能说明
给 Claude 一个 URL、粘贴一段文字,或描述一个主题——这个 skill 会自动设计成杂志质感 HTML 信息卡,并自动截图输出 PNG,可直接发到 X、小红书、微信。
核心特点:
- 瑞士国际主义 + 杂志编辑风格
- 大标题、强视觉张力
- Hook 模式(默认开启):每条描述改写为 10-20 字钩子句,有冲击感
- 支持 480 / 600 / 900px 宽度,说"生成 480 宽的卡片"即可切换
- 超长卡片(>1200px)自动分割成多张图
前置条件
- [ ] Chrome DevTools MCP 已安装并连接
- 用于无头截图(headless screenshot)
- 验证:Claude 能调用
navigate_page、take_screenshot - [ ] Python 3 + Pillow(用于超长图片分割)
- 安装:
pip3 install Pillow - 验证:
python3 -c "from PIL import Image; print('ok')"
安装
npx skills add joeseesun/info-card-designer触发方式
对 Claude 说:
- "生成信息卡"
- "做张信息卡"
- "把这段内容做成卡片"
- "信息卡片"
- "make info card" / "generate card"
使用示例
把这个链接做成信息卡:https://wise.readwise.io/issues/wisereads-vol-134/
把这段文字做成 480 宽的卡片
生成信息卡,保持原文描述Hook 模式开关
| 说法 | 效果 |
|---|---|
| 默认 | 自动将描述改写为 10-20 字钩子句 |
| "保持原文" / "不改描述" | 使用原始文字,不改写 |
常见问题
| 问题 | 解决方法 |
|---|---|
| 截图失败 | 检查 Chrome DevTools MCP 是否已连接 |
No module named PIL | 运行 pip3 install Pillow |
| 内容不对 / 有编造 | 提供原文链接或直接粘贴文本,重新触发 |
| 超长卡没有分割 | 确认 Pillow 已安装,高度 >1200px 才触发分割 |
致谢
设计风格灵感来自 @shao__meng 在 X 上的这篇分享: https://x.com/shao__meng/status/2027368489439334504
信息卡设计规范
字体引入
<link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@700;900&family=Noto+Sans+SC:wght@400;500;700&family=Oswald:wght@500;700&family=Inter:wght@400;600;700&display=swap" rel="stylesheet">字号规范(vw 单位,随宽度自动缩放)
核心原则:所有字号用 clamp(min, Xvw, max) 写,不写固定 px,确保 480/600/900 三种宽度比例一致。
| 层级 | CSS | 480px效果 | 600px效果 | 900px效果 |
|---|---|---|---|---|
| 主标题 | clamp(40px, 13vw, 130px) | ~62px | ~78px | ~117px |
| 条目标题 | clamp(16px, 4.5vw, 44px) | ~22px | ~27px | ~40px |
| 正文 | clamp(14px, 3.2vw, 24px) | ~15px | ~19px | ~28px |
| 辅助信息 | clamp(12px, 2.5vw, 20px) | ~12px | ~15px | ~22px |
| 元数据/标签 | clamp(10px, 2vw, 15px) | ~10px | ~12px | ~15px |
基础卡片 CSS
:root {
--color-bg: #f5f3ed;
--color-text: #1a1a1a;
--color-accent: #2c3e8c; /* 根据主题替换 */
--color-muted: #555;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
margin: 0;
background: var(--color-bg);
}
.card {
width: 600px;
background: var(--color-bg);
padding: 50px;
display: flex;
flex-direction: column;
gap: 30px;
position: relative;
overflow: hidden;
}
/* 噪点纹理 */
.card::before {
content: '';
position: absolute;
inset: 0;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.04'/%3E%3C/svg%3E");
pointer-events: none;
z-index: 0;
}
.card > * { position: relative; z-index: 1; }
/* 标题 */
.main-title {
font-family: 'Noto Serif SC', serif;
font-size: 80px;
font-weight: 900;
line-height: 1.0;
color: #0a0a0a;
letter-spacing: -0.03em;
}
/* 正文 */
.content-body {
font-family: 'Inter', 'Noto Sans SC', sans-serif;
font-size: 19px;
line-height: 1.6;
color: #1a1a1a;
}
/* Accent 装饰线 */
.accent-bar {
height: 6px;
background: var(--color-accent);
width: 80px;
}
.accent-bar-full {
height: 4px;
background: var(--color-accent);
width: 100%;
}
/* 标签 */
.label {
font-family: 'Oswald', 'Inter', sans-serif;
font-size: 13px;
font-weight: 700;
letter-spacing: 0.15em;
text-transform: uppercase;
color: var(--color-accent);
}
/* 背景色块 */
.bg-block {
background: rgba(0,0,0,0.03);
padding: 20px 24px;
border-left: 4px solid var(--color-accent);
}
/* 数字大字 */
.stat-number {
font-family: 'Oswald', 'Inter', sans-serif;
font-size: 120px;
font-weight: 700;
line-height: 1.0;
color: var(--color-accent);
letter-spacing: -0.05em;
}
/* 多栏布局 */
.grid-2col {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 30px 40px;
}
.grid-3col {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 20px 30px;
}
.col-divider {
border-left: 2px solid rgba(0,0,0,0.12);
padding-left: 30px;
}
/* 页脚/来源 */
.footer {
font-size: 13px;
color: #888;
letter-spacing: 0.05em;
border-top: 1px solid rgba(0,0,0,0.1);
padding-top: 15px;
margin-top: 10px;
}布局模板
模板 A:大字符主义(低密度内容)
适用:单一观点/数据/金句
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=900">
<link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@700;900&family=Noto+Sans+SC:wght@400;500;700&family=Oswald:wght@500;700&family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
<style>/* 基础CSS + 本模板样式 */</style>
</head>
<body>
<div class="card" style="min-height: 900px; justify-content: space-between;">
<!-- 顶部标签 -->
<div class="label">主题标签</div>
<!-- 核心内容区 -->
<div>
<div class="accent-bar" style="margin-bottom: 20px;"></div>
<h1 class="main-title" style="font-size: 96px;">核心<br>观点</h1>
</div>
<!-- 补充说明 -->
<div class="content-body" style="max-width: 600px;">
一句补充说明文字,字号 18-20px,清晰可读。
</div>
<!-- 页脚 -->
<div class="footer">来源 / 出处 · 日期</div>
</div>
</body>
</html>模板 B:标准单栏(中密度内容)
适用:2-4 个要点、文章摘要
<div class="card">
<!-- 顶部 -->
<div style="display: flex; align-items: center; gap: 16px;">
<div class="label">分类</div>
<div class="accent-bar"></div>
</div>
<!-- 主标题 -->
<div>
<h1 class="main-title" style="font-size: 56px;">文章主标题</h1>
<p class="content-body" style="margin-top: 12px; color: #555;">副标题或一句话摘要</p>
</div>
<!-- 分割线 -->
<div class="accent-bar-full"></div>
<!-- 正文要点 -->
<div class="content-body">
<p>第一个要点,正文 18-19px,行高 1.6。</p>
<div class="bg-block" style="margin: 16px 0;">
<p>重点引用或数据,放在色块中突出。</p>
</div>
<p>第二个要点,继续描述。</p>
</div>
<!-- 页脚 -->
<div class="footer">@vista8 · 向阳乔木推荐看</div>
</div>模板 C:多栏网格(高密度内容)
适用:5+ 要点、对比、列表
<div class="card">
<!-- 顶部标题 -->
<div>
<div class="label">专题</div>
<h1 class="main-title" style="font-size: 48px; margin-top: 8px;">标题</h1>
<div class="accent-bar-full" style="margin-top: 16px;"></div>
</div>
<!-- 2栏内容 -->
<div class="grid-2col">
<div>
<div class="label" style="margin-bottom: 8px;">Part 01</div>
<h2 style="font-size: 24px; font-weight: 700; margin-bottom: 10px;">子标题</h2>
<p class="content-body">内容文字,18px,清晰可读。</p>
</div>
<div class="col-divider">
<div class="label" style="margin-bottom: 8px;">Part 02</div>
<h2 style="font-size: 24px; font-weight: 700; margin-bottom: 10px;">子标题</h2>
<p class="content-body">内容文字,18px,清晰可读。</p>
</div>
</div>
<!-- 页脚 -->
<div class="footer">@vista8 · 向阳乔木推荐看</div>
</div>X (Twitter) 优化要点
1. 固定宽度 900px:X 展示图片时按比例缩放,900px 保证文字不会过小 2. viewport meta:<meta name="viewport" content="width=900"> 防止浏览器缩放 3. 推荐比例:1:1 (900×900) 或 16:9 (900×506) 效果最佳 4. 截图用 fullPage=true:捕获完整卡片,不裁剪 5. 字号底线:任何可读文字 不低于 16px,正文 不低于 18px
配色方案
| 主题 | accent 颜色 | 适用场景 |
|---|---|---|
| 靛蓝 | #2c3e8c | 知识/科技/AI |
| 深红 | #c0392b | 警示/激情/重要 |
| 墨绿 | #1a4a3a | 生活/健康/自然 |
| 深金 | #8b6914 | 财经/商业/价值 |
| 深灰 | #2c2c2c | 中性/通用/严肃 |
| 紫罗兰 | #5b2d8e | 创意/哲学/艺术 |
#!/usr/bin/env python3
"""
Split a tall info card image into multiple equal-height slices.
Usage: python3 split_card.py <image_path> [max_height=1200]
Output: card-1.png, card-2.png, ... in same directory as input
"""
import sys
import os
from PIL import Image
def split_card(image_path, max_height=1200):
img = Image.open(image_path)
width, height = img.size
if height <= max_height:
print(f"No split needed ({height}px ≤ {max_height}px)")
return [image_path]
base_dir = os.path.dirname(image_path)
base_name = os.path.splitext(os.path.basename(image_path))[0]
# Remove existing -N suffix if re-splitting
if base_name.endswith(("-1", "-2", "-3", "-4")):
base_name = base_name[:-2]
num_parts = (height + max_height - 1) // max_height
# Distribute height evenly to avoid a tiny last slice
slice_height = height // num_parts
parts = []
for i in range(num_parts):
top = i * slice_height
bottom = height if i == num_parts - 1 else (i + 1) * slice_height
cropped = img.crop((0, top, width, bottom))
out_path = os.path.join(base_dir, f"{base_name}-{i+1}.png")
cropped.save(out_path, "PNG")
parts.append(out_path)
print(f" Saved: {out_path} ({bottom - top}px)")
return parts
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: split_card.py <image_path> [max_height=1200]")
sys.exit(1)
path = sys.argv[1]
max_h = int(sys.argv[2]) if len(sys.argv) > 2 else 1200
result = split_card(path, max_h)
print(f"\nResult: {len(result)} file(s)")
for p in result:
print(f" {p}")