Align
提供文本、内存、CSS布局及序列对齐的快速参考,适用于开发与格式化场景。
自动检测并修复 Next.js 站点中图片的裁剪问题,优化 object-position 值。
openclaw skills install @kaicianflone/thumbnail-qa命令、参数、文件名以原文为准
此技能会遍历 Next.js 站点的每一页,检测容器中裁剪不当的图片,基于焦点分析计算最优的 object-position 值,并应用细粒度的 CSS 修复——每个修复都附带前后截图和独立的原子提交。
# 查找 browse 可执行文件
B=$(command -v browse 2>/dev/null || echo "$HOME/.claude/skills/gstack/browse/bin/browse")
# 验证 browse 是否可用
if [ ! -x "$B" ]; then
echo "错误:在 $B 处未找到 browse 可执行文件"
echo "请安装 gstack 或确保 browse 在 PATH 中。"
exit 1
fi运行 git status --porcelain。如果输出非空,向用户询问:
“您的工作区存在未提交的更改。在运行缩略图质量检查前,您希望:
- 现在提交更改
- 保存更改(git stash)
- 中止并手动处理
请选择一项?”
仅当工作区干净(或用户明确选择第 3 项并理解风险)后才继续。
# 检查开发服务器是否运行
curl -s -o /dev/null -w "%{http_code}" http://localhost:3000 | grep -q "200\|301\|302" && echo "运行中" || echo "未运行"若未运行,启动它:
npm run dev &
DEV_PID=$!
# 等待服务器就绪(最长 30 秒)
for i in $(seq 1 30); do
curl -s -o /dev/null -w "%{http_code}" http://localhost:3000 | grep -q "200\|301\|302" && break
sleep 1
done# 设置视口
$B viewport 1280x800
# 创建输出目录
mkdir -p .gstack/thumbnail-qa/screenshots
# 确保 .gstack/ 被加入 .gitignore
if ! grep -q "^\.gstack/" .gitignore 2>/dev/null; then
echo ".gstack/" >> .gitignore
git add .gitignore
git commit -m "chore: 将 .gstack/ 加入 .gitignore"
figrep -rn "<Image" --include="*.tsx" --include="*.ts" --include="*.jsx" --include="*.js" . \
| grep -v "node_modules" \
| grep "fill"对每个匹配到的文件,使用 Read 工具完整读取整个文件(而非仅 25 行窗口)。必须理解组件全部内容,才能正确解析条件类名和动态 src 值。
对每个带有 fill 属性的 <Image,记录以下信息:
| 字段 | 说明 |
|---|---|
id | 顺序编号(1, 2, 3, ...) |
file_path | TSX 文件的绝对路径 |
line_number | <Image 所在行号 |
page_route | URL 路径(例如 /, /about, /connect) |
src | src 属性的值(字符串或表达式) |
className | 完整的 className 字符串或表达式 |
current_position | 提取的 object-position 类(如 object-top、object-[50%_25%] 或 none) |
container_classes | 包裹 div 的类(特别是 overflow-hidden、aspect-*、h-*、w-*) |
conditional_key | 若 className 为条件类,则记录其依赖字段或表达式 |
notes | 任何动态或条件复杂性说明 |
跳过满足以下任一条件的图像:
fill 属性src 包含 "logo"(不区分大小写)rounded-full 类(用于头像/图标样式)object-contain(有意留黑边)动态 src(如 src={photo.src} 或 src={item.image}):
条件类名(如 className={category.id === 'worship' ? 'object-top' : 'object-center'}):
conditional_key 记录为条件驱动字段(如 category.id)打印所有候选图像的编号列表:
图像注册表(共 N 个候选)
================================
[1] src: /images/team/alice.jpg
route: /about
file: components/TeamSection.tsx:42
当前位置: object-top
容器: relative overflow-hidden h-64 w-full
[2] src: (动态) photo.src — 来自 data/photos.ts 的 6 个条目
route: /gallery
file: components/Gallery.tsx:18
当前位置: object-center(静态)
conditional_key: 无
notes: 需分别展开 6 个 photo 条目
...预期总数:全站约 15 个条目。
将注册表中所有条目按 page_route 分组,以减少浏览器导航次数(每页只访问一次)。
对每页执行:
# 导航至页面
$B goto http://localhost:3000/PAGE_ROUTE
# 等待图片加载
sleep 1
# 截取父容器(overflow-hidden 容器)截图,而非 img 标签
$B screenshot ".gstack/thumbnail-qa/screenshots/IMAGE_ID-current.png" \
--selector "div.relative.overflow-hidden:has(img[src*='FILENAME'])"若选择器失败(动态 src、复杂 DOM),回退使用:
$B screenshot ".gstack/thumbnail-qa/screenshots/IMAGE_ID-current.png" \
--selector "CLOSEST_IDENTIFIABLE_PARENT"在分析备注中记录所用选择器。
使用 Read 工具查看 public/ 目录中的原始图像:
Read: public/images/PATH_TO_IMAGE.jpg这可提供未裁剪图像的完整视觉参考。
分析完整图像并进行分类:
| 图片类型 | 焦点优先级规则 |
|---|---|
| 人物 / 人像 | 面部完全可见,从额头到下巴。眼睛位于容器上三分之一区域。 |
| 群体 / 团队 | 尽可能展示更多人脸。优先水平居中。避免裁切任何人。 |
| 建筑 / 建筑物 | 展示完整结构。若可能,屋顶线和入口均应可见。 |
| 宗教 / 活动 / 事件 | 保持主要动作或发言者在画面内。避免裁切手部或手势。 |
| 风景 / 场景 | 主体居中;地平线位置根据天空与地面的视觉兴趣决定。 |
将焦点坐标记录为百分比形式:X_PERCENT% Y_PERCENT%(例如 50% 25%)。
将截图中的裁剪效果与焦点规则进行对比,判断:
请勿将图像标记为“需要修复”,如果当前位置已满足焦点规则。 若 object-top 已正确显示面部,请保留原值。不要用可能更差的计算值替换已生效的值。目标是精心筛选的结果,而非统一的语法格式。
**object-position 的工作原理:** object-position: X Y 表示将图像的 X% 位置对齐容器的 X% 位置,Y% 位置对齐容器的 Y% 位置。
object-top (= 50% 0%) 将图像顶部对齐容器顶部。适用于高比例人像,面部位于上半部分的情况。object-center (= 50% 50%) 居中图像。当主体位于画面中央时适用。object-bottom (= 50% 100%) 将图像底部对齐容器底部。关键洞察: 对于高比例人像在短宽容器中的情况,容器默认会从图像中间裁剪出一条水平带。若要显示图像顶部附近的内容,应使用 object-top 或极低的 Y 值(0%-10%)。例如 object-[50%_20%] 并不表示“显示顶部 20%”——它会使视图向下偏移,这与希望显示人物顶部内容的目标相反。
经验法则:
object-top 或 object-[50%_5%]object-center 即可object-top、object-center)可用时优先使用——仅在确实需要微调时才使用任意值四舍五入至最接近的 5% 以获得更整洁的数值。
每张图片记录分析结果:
[1] alice.jpg — NEEDS_FIX
图片类型:人像(高比例图像,面部靠近顶部)
焦点位置:50% 20%(面部,眼睛靠近图像上部)
当前设置:object-center(面部被裁切——容器显示图像中部)
推荐设置:object-top
原因:面部位于高比例人像的上半部分——object-top 将图像顶部对齐容器顶部,以确保面部可见
[2] group-photo.jpg — OK
图片类型:群体
焦点位置:50% 40%(人脸集中在中心区域)
当前设置:object-top
推荐设置:保持当前
原因:object-top 已正确显示所有面部——不应替换已有效的工作值按顺序处理每个标记为“需要修复”的图像。
$B goto http://localhost:3000/PAGE_ROUTE
sleep 1
$B screenshot ".gstack/thumbnail-qa/screenshots/IMAGE_ID-before.png" \
--selector "div.relative.overflow-hidden:has(img[src*='FILENAME'])"根据注册表条目选择正确的编辑模式:
模式 A — 静态 className 字符串
查找现有的 object-* 类名(或插入位置),替换或添加:
// 修复前
className="relative overflow-hidden h-64 object-center"
// 修复后
className="relative overflow-hidden h-64 object-[50%_25%]"使用编辑工具操作。不得修改 className 中的其他部分。
模式 B — 条件三元表达式(基于字段)
将三元表达式替换为基于相同字段的定位映射:
// 修复前(基于 category.id)
className={`... ${category.id === 'worship' ? 'object-top' : 'object-center'}`}
// 修复后(定位映射,相同键:category.id)
const positionMap: Record<string, string> = {
worship: 'object-[50%_20%]',
music: 'object-[50%_35%]',
community: 'object-[50%_45%]',
}
// 在 JSX 中:
className={`... ${positionMap[category.id] ?? 'object-center'}`}若条件基于 photo.caption 或类似字符串内容而非 ID,建议在数据对象中新增 position 字段,并从中读取值。
**模式 C — 已存在的 object-[X_Y] 自定义值**
仅替换自定义值部分:
// 修复前
object-[50%_50%]
// 修复后
object-[50%_25%]sleep 2$B screenshot ".gstack/thumbnail-qa/screenshots/IMAGE_ID-after.png" \
--selector "div.relative.overflow-hidden:has(img[src*='FILENAME'])"将修复前和修复后的截图并列显示。然后重新应用步骤 2.4 的焦点规则,针对修复后的截图进行检查:
如果修复后的截图未能通过修复前已通过的焦点规则,则说明修复使情况变得更糟。 这是最常见的失败情形——计算出的位置看似合理,但实际裁剪效果反而更差。
技能:缩略图质量检查(Thumbnail QA)
版本:1.0.0
分块:3/3
className)MANUAL_REVIEW,并添加备注:computed position {X} degraded framing vs original {Y}若修复后的截图存在歧义(改进不明显,无法判断是否更优):应标记为 MANUAL_REVIEW 而非直接提交。优先保留原始位置。
仅当修复后的截图明显优于原图时,方可提交。
确认修复有效后:
git add PATH/TO/CHANGED_FILE.tsx
git commit -m "style: reposition FILENAME thumbnail — REASON"
# 示例:
# git commit -m "style: reposition alice.jpg thumbnail — pull frame up to keep face centered"每张图片一个提交。例外情况:若多个图片共享同一文件中的同一条件逻辑块(例如一个位置映射覆盖组件中 6 张图片),可将它们一起提交,并在提交信息中列出所有受影响的图片。
汇总每张图片的处理结果:
THUMBNAIL QA REPORT
===================
Date: YYYY-MM-DD
Viewport: 1280x800
Pages checked: N
RESULTS SUMMARY
---------------
Total candidates checked: N
OK (no fix needed): N
Repositioned: N
Skipped (filtered): N
Manual review needed: N
REPOSITIONED IMAGES
-------------------
| # | Image | Page | Before Class | After Class | Reason |
|---|-------|------|--------------|-------------|--------|
| 1 | alice.jpg | /about | object-top | object-[50%_15%] | Face centered with forehead visible |
...
OK IMAGES (no change)
---------------------
| # | Image | Page | Position | Notes |
...
SKIPPED IMAGES
--------------
| # | Image | Reason |
...
MANUAL REVIEW NEEDED
--------------------
| # | Image | Page | Attempted Fix | Issue |
...
COMMITS
-------
abc1234 style: reposition alice.jpg thumbnail — ...
def5678 style: reposition team-photo.jpg thumbnail — ...
SCREENSHOTS
-----------
.gstack/thumbnail-qa/screenshots/REPORT_DATE=$(date +%Y-%m-%d)
REPORT_PATH=".gstack/thumbnail-qa/report-${REPORT_DATE}.md"
# 将上述结构化报告写入 $REPORT_PATH"缩略图质量检查已完成。共对 N 张图片进行重新定位,覆盖 N 个页面。报告已保存至
.gstack/thumbnail-qa/report-YYYY-MM-DD.md。下次上传图片后,请再次运行/thumbnail-qa。"
已收录 2 个 Skill