diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 040a2ec..2b5e3a8 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -1,8 +1,8 @@ { "name": "rnskill", - "version": "1.1.0", + "version": "1.2.0", "owner": "Pluviobyte", - "description": "雪踏乌云的 AI Agent Skills 集合 — 写作精修 + 动效制作 + 参考复刻 + 全帧质检", + "description": "雪踏乌云的 AI Agent Skills 集合 — 写作精修 + 内容提取 + 图像生成 + 动效制作 + 参考复刻 + 全帧质检", "repository": "https://github.com/Pluviobyte/rnskill", "license": "CC-BY-NC-4.0", "plugins": [ @@ -26,6 +26,16 @@ "keywords": ["视频", "动效", "导演", "motion", "director", "video"], "skills": ["./skills/rn-motion-director"] }, + { + "name": "rn-ian-xiaohei-cat-illustrations", + "description": "Ian 小黑猫怪诞正文配图。把中文文章中的判断、流程和隐喻转成 16:9 白底手绘插图,固定使用小黑猫 IP。改编自 Ian 的原版 Xiaohei Skill。\nIan-style Xiaohei Cat article illustrations with sparse hand-drawn 16:9 compositions and recurring character consistency.\nTrigger: /rn-ian-xiaohei-cat-illustrations, 小黑猫, 黑猫配图, 正文配图, 文章插图, 怪诞手绘, shot list", + "source": "./", + "strict": false, + "version": "1.0.0", + "category": "image-generation", + "keywords": ["小黑猫", "正文配图", "文章插图", "手绘", "shot list", "xiaohei", "illustration"], + "skills": ["./skills/rn-ian-xiaohei-cat-illustrations"] + }, { "name": "rn-motion-replica", "description": "把获授权的参考片段拆成视觉证据,并制作成原创、可编辑、可验证的 HyperFrames 动效工程。\nOriginal editable motion study from an authorized reference range, with analysis evidence and final-MP4 QC.\nTrigger: /rn-motion-replica, 参考这个视频做同款动效, 复刻前N秒方框连线动画", @@ -36,6 +46,16 @@ "keywords": ["参考视频", "动效复刻", "HyperFrames", "motion", "replica", "editable"], "skills": ["./skills/rn-motion-replica"] }, + { + "name": "rn-editorial-collage-motion", + "description": "半色调纸张拼贴动效。参考拆解 → 可编辑 JSON 规范 → Codex 静帧审批 → 本地逐层组装动画,无需 Arcads MCP。\nHalftone paper-collage motion with Codex-generated stills and local assemble-from-empty rendering. No Arcads MCP required.\nTrigger: /rn-editorial-collage-motion, 半色调拼贴, 纸张拼贴, 拼贴动效, 从无到有, editorial collage, halftone collage, animate this", + "source": "./", + "strict": false, + "version": "1.0.0", + "category": "video-production", + "keywords": ["半色调拼贴", "纸张拼贴", "拼贴动效", "从无到有", "halftone", "collage", "motion"], + "skills": ["./skills/rn-editorial-collage-motion"] + }, { "name": "rn-replica-qc", "description": "参考视频复刻 SOP v2。五级保真度 + 素材/运行时/交付三道全帧门 + 精确重放与参数化组件分离。\nReference replica SOP v2 with five fidelity levels and asset/runtime/delivery frame gates.\nTrigger: /rn-replica-qc, 复刻这个视频, 对齐参考视频, 逐帧像素验证", diff --git a/README.md b/README.md index 0f86cbe..7772f01 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ AI Agent Skills maintained by 雪踏乌云 for Codex, Claude Code, and other Agent workflows that support `SKILL.md`. -The collection covers Chinese writing, content extraction, motion direction, original reference-motion studies, style-specific video production, openers, and evidence-based replica QA. +The collection covers Chinese writing, content extraction, recurring-character illustration generation, motion direction, original reference-motion studies, halftone collage motion, style-specific video production, openers, and evidence-based replica QA. ## Requirements @@ -29,7 +29,7 @@ npx -y skills add Pluviobyte/rnskill -g --all Or install a single skill: ```bash -npx -y skills add Pluviobyte/rnskill --skill rn-renhua +npx -y skills add Pluviobyte/rnskill --skill rn-editorial-collage-motion ``` ### Manual Install @@ -41,11 +41,15 @@ Copy only the skill you need into your project: mkdir -p /.agents/skills cp -R skills/rn-renhua /.agents/skills/rn-renhua cp -R skills/rn-motion-replica /.agents/skills/rn-motion-replica +cp -R skills/rn-editorial-collage-motion /.agents/skills/rn-editorial-collage-motion +cp -R skills/rn-ian-xiaohei-cat-illustrations /.agents/skills/rn-ian-xiaohei-cat-illustrations # Claude Code mkdir -p /.claude/skills cp -R skills/rn-renhua /.claude/skills/rn-renhua cp -R skills/rn-motion-replica /.claude/skills/rn-motion-replica +cp -R skills/rn-editorial-collage-motion /.claude/skills/rn-editorial-collage-motion +cp -R skills/rn-ian-xiaohei-cat-illustrations /.claude/skills/rn-ian-xiaohei-cat-illustrations ``` ## Available Skills @@ -62,12 +66,19 @@ cp -R skills/rn-motion-replica /.claude/skills/rn-motion-replica |-------|-------------| | [`rn-wechat-extract`](skills/rn-wechat-extract/) | Extract full text from WeChat public account articles via MicroMessenger UA spoofing. Stdlib only, no API key. | +### Image Generation + +| Skill | Description | +|-------|-------------| +| [`rn-ian-xiaohei-cat-illustrations`](skills/rn-ian-xiaohei-cat-illustrations/) | Generates sparse 16:9 Chinese article illustrations with a recurring deadpan Xiaohei Cat character, white hand-drawn compositions, short colored annotations, and explicit identity-consistency QA. | + ### Video Production | Skill | Description | |-------|-------------| | [`rn-motion-director`](skills/rn-motion-director/) | Motion-first AI video director. Turns topics into motion video concepts with visual metaphors, beat graphs, and anti-PPT QC. | | [`rn-motion-replica`](skills/rn-motion-replica/) | Builds an original, editable HyperFrames motion study from an authorized reference range, with analysis evidence and final-MP4 QC. | +| [`rn-editorial-collage-motion`](skills/rn-editorial-collage-motion/) | Turns a reference or short brief into an editable halftone paper-collage spec, approved Codex-generated stills, and deterministic assemble-from-empty motion rendered locally with FFmpeg or HyperFrames. | | [`rn-dark-saas-video`](skills/rn-dark-saas-video/) | Dark cinematic SaaS product video in "magic UI" style. 8 scene blueprints, 3 timing presets, hard style rules. | | [`rn-bw-text-opener`](skills/rn-bw-text-opener/) | Black-white typed text opener animation with synced typing SFX. 3 timing presets. Includes a Python timing plan generator. | @@ -86,6 +97,8 @@ rnskill/ │ ├── rn-wechat-extract/ # Extraction: WeChat article reader │ ├── rn-motion-director/ # Video: motion director │ ├── rn-motion-replica/ # Video: original editable motion study +│ ├── rn-editorial-collage-motion/ # Video: halftone collage assembly +│ ├── rn-ian-xiaohei-cat-illustrations/ # Image: Xiaohei Cat article illustrations │ ├── rn-dark-saas-video/ # Video: dark SaaS style │ ├── rn-bw-text-opener/ # Video: typed text opener │ └── rn-replica-qc/ # QC: reference video replica @@ -105,9 +118,21 @@ python3 tools/sync-video-skills.py --source /path/to/video-production-skills python3 tools/sync-video-skills.py --source /path/to/video-production-skills --check ``` +## Credits and Adaptations + +### Xiaohei Cat Illustrations + +`rn-ian-xiaohei-cat-illustrations` is derived from Ian's original [Ian Xiaohei Illustrations](https://github.com/helloianneo/ian-xiaohei-illustrations), referred to here as the original Xiaohei Skill. It preserves the article-analysis, shot-list, white-background hand-drawn visual system, composition patterns, and calibration examples, then adapts the recurring black figure into a locally defined Xiaohei Cat IP with authoritative character references and stricter identity-consistency QA. The upstream project is MIT-licensed; its full copyright and license notice is retained in [`origin-and-license.md`](skills/rn-ian-xiaohei-cat-illustrations/references/origin-and-license.md). This adaptation is not an official Ian release. + +### Collage Motion + +`rn-editorial-collage-motion` is an independent adaptation inspired by Vikash Kumar's original [Arcads Collage Motion Skill](https://buldrr.com/arcads-collage-motion-skill/). Credit goes to Vikash Kumar for the original two-stage idea: decode a reference into an editable visual specification, then animate approved collage stills as an assemble-from-empty sequence. + +The original workflow requires the Arcads MCP connector and Arcads credits, and uses Nano Banana 2 for stills plus Seedance 2.0 for motion. This repository edition replaces that service chain with Codex's built-in image generation and local FFmpeg or HyperFrames rendering. It therefore needs no Arcads MCP connection and consumes no Arcads credits, making it a free local-compatible edition for users who already have access to Codex; existing Codex access and local compute requirements still apply. This adaptation is not an official Arcads or original-author release. + ## License -CC BY-NC 4.0. See [LICENSE](LICENSE). +Unless otherwise noted, CC BY-NC 4.0. See [LICENSE](LICENSE). Adapted third-party components retain their upstream notices; the Xiaohei-derived files include Ian's MIT notice in [`origin-and-license.md`](skills/rn-ian-xiaohei-cat-illustrations/references/origin-and-license.md). ## Author diff --git a/README.zh.md b/README.zh.md index 72f59c0..ced6741 100644 --- a/README.zh.md +++ b/README.zh.md @@ -4,7 +4,7 @@ 雪踏乌云维护的 AI Agent Skills 集合,适用于 Codex、Claude Code 等支持 `SKILL.md` 的 Agent 工作流。 -当前覆盖中文写作、内容提取、动效导演、原创参考动效复刻、风格化视频、片头包装和带逐帧证据的复刻质检。 +当前覆盖中文写作、内容提取、固定角色插画生成、动效导演、原创参考动效复刻、半色调拼贴动效、风格化视频、片头包装和带逐帧证据的复刻质检。 ## 前置要求 @@ -29,7 +29,7 @@ npx -y skills add Pluviobyte/rnskill -g --all 安装单个 Skill: ```bash -npx -y skills add Pluviobyte/rnskill --skill rn-renhua +npx -y skills add Pluviobyte/rnskill --skill rn-editorial-collage-motion ``` ### 手动安装 @@ -41,11 +41,15 @@ npx -y skills add Pluviobyte/rnskill --skill rn-renhua mkdir -p /.agents/skills cp -R skills/rn-renhua /.agents/skills/rn-renhua cp -R skills/rn-motion-replica /.agents/skills/rn-motion-replica +cp -R skills/rn-editorial-collage-motion /.agents/skills/rn-editorial-collage-motion +cp -R skills/rn-ian-xiaohei-cat-illustrations /.agents/skills/rn-ian-xiaohei-cat-illustrations # Claude Code mkdir -p /.claude/skills cp -R skills/rn-renhua /.claude/skills/rn-renhua cp -R skills/rn-motion-replica /.claude/skills/rn-motion-replica +cp -R skills/rn-editorial-collage-motion /.claude/skills/rn-editorial-collage-motion +cp -R skills/rn-ian-xiaohei-cat-illustrations /.claude/skills/rn-ian-xiaohei-cat-illustrations ``` ## 可用技能 @@ -62,12 +66,19 @@ cp -R skills/rn-motion-replica /.claude/skills/rn-motion-replica |-------|------| | [`rn-wechat-extract`](skills/rn-wechat-extract/) | 微信公众号文章全文提取。通过 MicroMessenger UA 伪装绕过微信访问控制,纯标准库,无需 API key。 | +### 图像生成 + +| Skill | 说明 | +|-------|------| +| [`rn-ian-xiaohei-cat-illustrations`](skills/rn-ian-xiaohei-cat-illustrations/) | 为中文文章生成 16:9 白底手绘正文配图,以死认真、略怪诞的小黑猫为固定角色,并通过权威参考图和角色一致性评分保持 IP 稳定。 | + ### 视频制作 | Skill | 说明 | |-------|------| | [`rn-motion-director`](skills/rn-motion-director/) | AI 动效导演元 Skill。把选题/脚本转化为动效视频概念:视觉隐喻、运动语法、场景节拍图、Anti-PPT 质量门。 | | [`rn-motion-replica`](skills/rn-motion-replica/) | 从获授权的参考片段构建原创、可编辑的 HyperFrames 动效工程,附参考分析证据和最终 MP4 质检。 | +| [`rn-editorial-collage-motion`](skills/rn-editorial-collage-motion/) | 将参考图或简述拆成可编辑的半色调纸张拼贴规范,使用 Codex 生成并审批静帧,再用本地 FFmpeg 或 HyperFrames 制作“从空背景逐件组装”的确定性动画。 | | [`rn-dark-saas-video`](skills/rn-dark-saas-video/) | 暗色 SaaS 魔术短片。黑色星空舞台 + 紫色底光 + 大字动效 + 渐变 CTA。8 套场景蓝图、3 种时长预设。 | | [`rn-bw-text-opener`](skills/rn-bw-text-opener/) | 黑白文字打字机开场动画。纯黑背景 + 白色逐字打字 + 同步音效 + 文字替换效果。3 种时长预设,附带 Python 时序规划脚本。 | @@ -86,6 +97,8 @@ rnskill/ │ ├── rn-wechat-extract/ # 提取:微信公众号文章 │ ├── rn-motion-director/ # 视频:动效导演 │ ├── rn-motion-replica/ # 视频:原创可编辑动效复刻 +│ ├── rn-editorial-collage-motion/ # 视频:半色调拼贴组装动效 +│ ├── rn-ian-xiaohei-cat-illustrations/ # 图像:小黑猫正文配图 │ ├── rn-dark-saas-video/ # 视频:暗色 SaaS 风格 │ ├── rn-bw-text-opener/ # 视频:黑白打字开场 │ └── rn-replica-qc/ # 质检:参考视频复刻 @@ -105,9 +118,21 @@ python3 tools/sync-video-skills.py --source /path/to/video-production-skills python3 tools/sync-video-skills.py --source /path/to/video-production-skills --check ``` +## 致谢与改编说明 + +### 小黑猫正文配图 + +`rn-ian-xiaohei-cat-illustrations` 来源于 Ian 的原版 [Ian Xiaohei Illustrations](https://github.com/helloianneo/ian-xiaohei-illustrations),也就是原始 Xiaohei Skill(小黑 Skill)。当前版本保留了文章认知锚点分析、shot list、16:9 白底手绘视觉系统、构图方法和校准样例,并将原版黑色“小黑”角色进一步改造成固定“小黑猫”IP,增加权威角色参考图和更严格的身份一致性质检。原项目采用 MIT 许可,完整版权与许可证保留在 [`origin-and-license.md`](skills/rn-ian-xiaohei-cat-illustrations/references/origin-and-license.md)。本改编版不是 Ian 发布的官方版本。 + +### 半色调拼贴动效 + +`rn-editorial-collage-motion` 是基于 Vikash Kumar 原版 [Arcads Collage Motion Skill](https://buldrr.com/arcads-collage-motion-skill/) 思路制作的独立改编版。感谢 Vikash Kumar 提出的两阶段工作流:先把参考视觉解码为可编辑规范,再把获批的拼贴静帧做成“从无到有”的逐件组装动画。 + +原版工作流需要连接 Arcads MCP 并消耗 Arcads credits,静帧和视频分别使用 Nano Banana 2 与 Seedance 2.0。本仓库版本保留参考拆解、可编辑 JSON 规范、静帧审批和逐层组装逻辑,但将执行链路优化为 Codex 内置生图,加本地 FFmpeg 或 HyperFrames 渲染。因此它不需要 Arcads MCP,也不消耗 Arcads credits;对于已经可以使用 Codex 的用户,这是一个本地免费兼容版,但仍受用户自身 Codex 使用权限和本机算力条件影响。本改编版不是 Arcads 或原作者发布的官方版本。 + ## 许可证 -CC BY-NC 4.0。详见 [LICENSE](LICENSE)。 +除另有说明外,仓库采用 CC BY-NC 4.0,详见 [LICENSE](LICENSE)。改编自第三方的内容继续保留其上游许可;小黑 Skill 衍生文件中的 Ian MIT 许可见 [`origin-and-license.md`](skills/rn-ian-xiaohei-cat-illustrations/references/origin-and-license.md)。 ## 作者 diff --git a/VERSION b/VERSION index 9084fa2..26aaba0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.0 +1.2.0 diff --git a/skills/rn-editorial-collage-motion/SKILL.md b/skills/rn-editorial-collage-motion/SKILL.md new file mode 100644 index 0000000..7983554 --- /dev/null +++ b/skills/rn-editorial-collage-motion/SKILL.md @@ -0,0 +1,139 @@ +--- +name: rn-editorial-collage-motion +description: 将参考图或简要描述解码为可编辑的半色调纸张拼贴规范,默认使用 Codex 内置 image_gen 生成品牌一致的静帧和透明图层,再用本地 FFmpeg 或 HyperFrames 制作“从空背景逐件组装”的确定性动态视频。用户提到半色调拼贴、纸张拼贴、剪纸拼贴、编辑式拼贴、杂志拼贴、复古印刷拼贴、拼贴动效、拼贴动画、剪纸动画、纸片组装、逐层组装、从无到有、元素飞入拼装、定格拼贴、定格动画、Arcads 风格、参考图拆解、风格拆解、反向拆解视觉、照这个风格做、做类似的、生成拼贴静帧、让这张图动起来、让这些元素组装起来、制作拼贴广告或拼贴解释视频时使用。英文触发语义包括 editorial collage、halftone collage、paper collage、paper-cut motion、stop-motion graphic、assemble from empty、build-on motion、analyze this、break this down、reverse-engineer this look、generate the stills、animate this、make these move。默认不调用 Arcads、Nano Banana、Seedance 或 Kling;只有用户明确要求且对应连接器可用时才进入外部生成路径。 +--- + +# 半色调拼贴动效 + +把创作分成两段:先将视觉解码为可编辑规范,再从获批静帧或透明图层构建动画。默认使用本地兼容工作流,真实记录每个生成器和渲染器。 + +## 选择交付范围 + +先判断用户要哪一层: + +1. 仅分析:交付拆解、通用提示词和 JSON 视觉规范。 +2. 仅静帧:完成分析并生成、筛选静帧。 +3. 拼贴动效:完成静帧审批后制作无声动画底片。 +4. 完整视频:把本 Skill 作为视觉阶段,继续服从视频生产契约、字幕、配音、数字人和归档规则。 + +缺参考图但用户明确要求“照这张图分析”时,先索取图片。只有简述时,直接草拟规范,不重复询问已知信息。 + +## 选择执行路径 + +默认采用本地路径: + +- 静帧或图层:加载 `imagegen` Skill,使用 Codex 内置 `image_gen`。不得默认切换到 OpenAI API、CLI 或其他生图模型。 +- 简单逐层组装:使用 `scripts/render_assembly.py`。 +- 复杂排版、多个转场或组件级时间轴:加载 `hyperframes` Skill,沿用本规范和来源声明。 + +只有用户明确要求 Arcads、Nano Banana、Seedance 或 Kling,并且对应工具在当前会话可调用时,才读取 `references/provider-boundaries.md` 并进入外部路径。上传本地品牌图、产品图或人物图前,必须说明上传位置、费用和用途并取得用户确认。 + +不得根据提示词、文件名或预期模型推断实际提供方。未实际调用的模型只能写成“目标提示词”或“兼容风格”,不能写成输出来源。 + +## 默认生产链路(硬默认) + +严格按以下顺序执行: + +1. 解码参考图或简述,生成拆解、通用提示词和 JSON 视觉规范。 +2. 使用 Codex 内置 `image_gen` 为每幕单独生成完整静帧。品牌图、产品图或人物参考要在所有相关调用中保持可见。 +3. 把生成结果从 Codex 默认生成目录复制到工程 `assets/stills/`,不得让工程长期引用 `$CODEX_HOME/generated_images/` 下的文件。 +4. 向用户展示完整静帧。用户未明确确认静帧前,禁止生成动画、FFmpeg 组装计划或正式视频。 +5. 静帧确认后,使用 Codex 内置 `image_gen` 生成各独立剪纸元素。需要透明 PNG 时,先生成纯色 chroma-key 背景,再调用 `imagegen` Skill 指定的 `remove_chroma_key.py` 本地抠像,并通过 alpha 预检。 +6. 使用获批静帧锁定最终构图,用透明图层建立 `assembly-plan.json`,再用本地 FFmpeg 或 HyperFrames 从空背景逐件组装。 +7. 完成媒体探针、关键帧检查和来源 manifest。默认记录 `actual_still_provider: codex-image-gen`、`actual_motion_provider: local-ffmpeg` 或 `hyperframes`、`external_uploads: false`。 + +如果用户直接提供全部静帧或透明图层,把 `actual_still_provider` 改为 `user-supplied`。只有真实发生外部调用时才能填写 Arcads、Nano Banana、Seedance 或 Kling。 + +## 阶段 A:解码参考 + +首次解码时完整阅读 `references/visual-contract.md` 和 `references/schemas.md`。按以下顺序输出: + +1. `### 拆解`:媒介与工艺、色场、元素与切边、构图与层级、单幕创意、文字、安全区、情绪。 +2. `### 通用提示词`:写成不依赖“上图”的自包含自然语言提示词。 +3. `### JSON 规范`:从 `assets/templates/collage-spec.json` 复制并填写,保持有效 JSON。 + +把观察写成可复现参数。例如写“黑白圆点半色调,约 65 lpi,白色细描边,右下 6px 柔和阴影”,不要只写“有纸感”。 + +多张参考图要分别解码,再补一段共同风格摘要。用户要求“保持外观,只改颜色”时,只改相应字段,但重新输出完整 JSON。 + +## 阶段 B:规划场景 + +每幕只保留一个核心创意。为每幕锁定: + +- 背景色和画幅。 +- 主要元素、辅助元素、层级和最终坐标。 +- 文字内容、排版和可编辑方式。 +- 从空背景到完整构图的进入顺序。 +- 真人、数字人、字幕、Logo 和平台 UI 的避让区。 + +从 `assets/templates/assembly-plan.json` 建立组装计划。正式成片优先使用 `layered` 模式,每个元素提供一张带透明通道的 PNG。`bands` 模式只是将整张静帧切成条带滑入,只能用于快速预览或用户明确接受的简化版本。 + +## 阶段 C:生成与审批静帧 + +加载 `imagegen` Skill,使用 Codex 内置 `image_gen` 先生成或组合完整静帧,再展示给用户审批。保持品牌或产品参考在所有相关生成调用中可见。 + +本地正式模式按以下顺序工作: + +1. 每幕发起一次独立的内置 `image_gen` 调用,生成完整构图静帧;不同场景不要用一次调用拼成大图。 +2. 把选中的静帧复制到工程 `assets/stills/`,记录最终提示词和参考图角色。 +3. 展示静帧并获得用户明确确认。未确认时只允许调整提示词和重新生成。 +4. 确认后再生成独立拼贴元素。按 `imagegen` 的 chroma-key 加本地抠像路径取得透明 PNG,保留白色 keyline 和柔和阴影。 +5. 用获批静帧校准图层的大小、坐标和层级。文字默认保留为 HyperFrames、HTML 或 Remotion 的可编辑文本层。 +6. 导出场景静帧和图层清单,再进入动画阶段。 + +内置 `image_gen` 不可用或失败时,不得自动改用 CLI。先告知用户 CLI/API 路径需要 `OPENAI_API_KEY`,只在用户明确同意后切换。 + +如果只拿到一张完整静帧,可以先用 `bands` 模式做低成本运动预览,但不得把矩形条带滑入描述成真正的“逐元素组装”。 + +## 阶段 D:本地逐层组装 + +先验证规范和计划: + +```bash +COLLAGE_SKILL_DIR="/absolute/path/to/rn-editorial-collage-motion" +python3 "$COLLAGE_SKILL_DIR/scripts/validate_collage.py" \ + --spec /absolute/path/collage-spec.json \ + --plan /absolute/path/assembly-plan.json \ + --project /absolute/path/project +``` + +再渲染无声底片: + +```bash +python3 "$COLLAGE_SKILL_DIR/scripts/render_assembly.py" \ + --project /absolute/path/project \ + --plan /absolute/path/assembly-plan.json \ + --output /absolute/path/project/renders/collage-assembly.mp4 +``` + +动画必须从纯色空场开始,元素按计划从画面边缘进入并落位。禁止用镜头晃动、整图漂移或持续缩放冒充组装。落位后留足可读时间。 + +## 阶段 E:质检和来源声明 + +完整阅读 `references/qc-and-provenance.md`,至少完成: + +- 媒体探针:尺寸、比例、帧率、时长、编码和可解码性。 +- 首帧、每幕落位前后、幕中点和末帧抽查。 +- 空场起步、逐件进入、阴影稳定、文字可读、安全区和画面密度检查。 +- `render-manifest.json` 与实际输出、输入计划和生成器一致。 + +在制作说明中明确写出: + +- `actual_still_provider` +- `actual_motion_provider` +- `external_uploads` +- 是否属于 `compatible_render`,以及兼容的是哪套视觉规范 + +当前会话没调用 Arcads MCP 时,固定使用“Arcads 风格兼容渲染”或“editorial collage 本地渲染”,不得写成 Nano Banana 或 Seedance 原生输出。 + +## 资源 + +- `references/visual-contract.md`:风格词汇、硬性视觉合同和反例。 +- `references/schemas.md`:视觉规范与组装计划字段说明。 +- `references/provider-boundaries.md`:本地和外部生成路径的权限与披露边界。 +- `references/qc-and-provenance.md`:交付质检和来源记录。 +- `assets/templates/collage-spec.json`:可复制的视觉规范模板。 +- `assets/templates/assembly-plan.json`:可复制的本地组装计划模板。 +- `assets/templates/assembly-plan-bands.json`:只有完整静帧时使用的条带预览模板。 +- `scripts/validate_collage.py`:规范、计划和素材预检。 +- `scripts/render_assembly.py`:FFmpeg 确定性逐层或条带组装器。 diff --git a/skills/rn-editorial-collage-motion/agents/openai.yaml b/skills/rn-editorial-collage-motion/agents/openai.yaml new file mode 100644 index 0000000..15a72b5 --- /dev/null +++ b/skills/rn-editorial-collage-motion/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "半色调拼贴动效" + short_description: "参考图拆解、Codex 拼贴生图与本地逐层组装动画制作" + default_prompt: "Use $rn-editorial-collage-motion to analyze this reference, generate approved halftone collage stills with Codex, and assemble the motion locally." diff --git a/skills/rn-editorial-collage-motion/assets/templates/assembly-plan-bands.json b/skills/rn-editorial-collage-motion/assets/templates/assembly-plan-bands.json new file mode 100644 index 0000000..016c357 --- /dev/null +++ b/skills/rn-editorial-collage-motion/assets/templates/assembly-plan-bands.json @@ -0,0 +1,28 @@ +{ + "version": 1, + "canvas": { + "width": 1080, + "height": 1920, + "fps": 30 + }, + "provenance": { + "actual_still_provider": "codex-image-gen", + "actual_motion_provider": "local-ffmpeg", + "external_uploads": false, + "compatible_render": true, + "compatible_with": "rn-editorial-collage-motion visual contract" + }, + "scenes": [ + { + "id": "scene-01-preview", + "duration_s": 3.0, + "background_hex": "#1F3FB0", + "mode": "bands", + "still": "assets/stills/scene-01-finished.png", + "bands": 3, + "entry_s": 0.72, + "stagger_s": 0.18, + "first_from": "left" + } + ] +} diff --git a/skills/rn-editorial-collage-motion/assets/templates/assembly-plan.json b/skills/rn-editorial-collage-motion/assets/templates/assembly-plan.json new file mode 100644 index 0000000..e8bb626 --- /dev/null +++ b/skills/rn-editorial-collage-motion/assets/templates/assembly-plan.json @@ -0,0 +1,47 @@ +{ + "version": 1, + "canvas": { + "width": 1080, + "height": 1920, + "fps": 30 + }, + "provenance": { + "actual_still_provider": "codex-image-gen", + "actual_motion_provider": "local-ffmpeg", + "external_uploads": false, + "compatible_render": true, + "compatible_with": "rn-editorial-collage-motion visual contract" + }, + "scenes": [ + { + "id": "scene-01", + "duration_s": 3.0, + "background_hex": "#1F3FB0", + "mode": "layered", + "pieces": [ + { + "source": "assets/pieces/scene-01-label.png", + "x": 80, + "y": 120, + "entry": { + "from": "left", + "start_s": 0.1, + "end_s": 0.55, + "distance_px": 900 + } + }, + { + "source": "assets/pieces/scene-01-subject.png", + "x": 420, + "y": 330, + "entry": { + "from": "right", + "start_s": 0.45, + "end_s": 1.25, + "distance_px": 1200 + } + } + ] + } + ] +} diff --git a/skills/rn-editorial-collage-motion/assets/templates/collage-spec.json b/skills/rn-editorial-collage-motion/assets/templates/collage-spec.json new file mode 100644 index 0000000..9d9e7dd --- /dev/null +++ b/skills/rn-editorial-collage-motion/assets/templates/collage-spec.json @@ -0,0 +1,44 @@ +{ + "medium": "halftone print collage", + "craft_style": "editorial halftone paper collage on a flat color field", + "aspect_ratio": "9:16", + "style_signature": "flat cobalt field, black-and-white halftone cut-outs, crisp white keylines, soft low-opacity shadows, one clear editorial idea", + "color_field": { + "background_hex": "#1F3FB0", + "evenness": "perfectly flat, no gradient", + "paper_grain": "fine uncoated-paper fiber" + }, + "elements": [ + { + "id": "subject", + "what": "replace with the primary subject", + "role": "primary subject", + "halftone": "fine round-dot, approximately 70 lpi, black-and-white", + "cut_edge": "crisp machine-cut with a thin white paper keyline", + "drop_shadow": "6px down-right, soft, 30 percent opacity", + "color_treatment": "black-and-white halftone", + "placement": "upper-right, clear of reserved areas" + } + ], + "palette_hex": ["#1F3FB0", "#0A0A0A", "#FFFFFF"], + "composition": { + "layout": "asymmetric rule of thirds", + "depth_layers": "field, supporting pieces, primary subject, label", + "negative_space": "generous space around the primary subject", + "balance": "visual weight high and right", + "reserved_areas": ["lower-left quarter reserved for avatar"] + }, + "idea": "replace with one visual idea", + "label": { + "present": true, + "content": "替换标签", + "font_character": "bold geometric sans", + "weight": "heavy", + "placement": "upper-left", + "treatment": "editable white paper text layer", + "editable": true + }, + "mood": "clear, premium, energetic", + "references_era": "contemporary editorial print collage", + "negative_prompt": "no gradient, no gloss, no 3D render, no busy background, no camera wobble" +} diff --git a/skills/rn-editorial-collage-motion/references/provider-boundaries.md b/skills/rn-editorial-collage-motion/references/provider-boundaries.md new file mode 100644 index 0000000..3f69de1 --- /dev/null +++ b/skills/rn-editorial-collage-motion/references/provider-boundaries.md @@ -0,0 +1,40 @@ +# Provider Boundaries + +## 本地默认路径 + +- 静帧:加载 `imagegen` Skill,固定优先使用 Codex 内置 `image_gen`;用户提供图片时记录为 `user-supplied`。 +- 透明图层:仍使用内置 `image_gen` 生成纯色 chroma-key 版本,再用 `$CODEX_HOME/skills/.system/imagegen/scripts/remove_chroma_key.py` 本地抠像并验证 alpha。 +- 动画:使用 `local-ffmpeg` 或 HyperFrames。 +- 上传:默认无外部上传。 +- 来源声明:写明 `compatible_render: true`,不要声称 Arcads、Nano Banana、Seedance 或 Kling 原生输出。 + +默认链路固定为:参考解码 → Codex `image_gen` 完整静帧 → 用户确认 → Codex `image_gen` 独立图层 → 本地抠像 → FFmpeg/HyperFrames 组装 → QC 和 manifest。 + +Codex 内置 `image_gen` 生成的项目素材必须复制到项目目录,不能让工程长期引用 `$CODEX_HOME/generated_images/`。内置工具失败时不得自动切换 CLI/API;只有用户明确同意且本机已有 `OPENAI_API_KEY` 才能使用 fallback。 + +## Arcads 或其他外部路径 + +只有同时满足以下条件才执行: + +1. 用户明确要求使用该提供方或模型。 +2. 当前会话实际暴露对应连接器或工具。 +3. 已核对当次工具 schema、模型名称、价格和限制。 +4. 上传本地文件前已告知用户目的、上传位置和可能费用,并取得确认。 + +如果只具备提示词,没有连接器,只输出可复制的提示词和 JSON,不伪造调用结果。 + +## 来源记录 + +每次交付记录: + +```json +{ + "actual_still_provider": "codex-image-gen | user-supplied | arcads-nano-banana-2 | other", + "actual_motion_provider": "local-ffmpeg | hyperframes | arcads-seedance-2.0 | arcads-kling-3.0-pro | other", + "external_uploads": false, + "compatible_render": true, + "compatible_with": "rn-editorial-collage-motion visual contract" +} +``` + +只记录实际发生的调用。目标提示词和计划模型放在单独字段,不能覆盖 `actual_*`。 diff --git a/skills/rn-editorial-collage-motion/references/qc-and-provenance.md b/skills/rn-editorial-collage-motion/references/qc-and-provenance.md new file mode 100644 index 0000000..01f2f35 --- /dev/null +++ b/skills/rn-editorial-collage-motion/references/qc-and-provenance.md @@ -0,0 +1,49 @@ +# QC and Provenance + +## 渲染前 + +- 运行 `validate_collage.py`,不得有错误。 +- 检查每张图层有透明通道、尺寸合理、没有意外背景块。 +- 确认首帧空场、进入顺序和最终坐标。 +- 确认文字和数字人避让区。 +- 获得用户对静帧或最终构图的明确确认。 + +## 渲染后 + +使用 `ffprobe` 检查: + +- 画幅、分辨率和像素格式正确。 +- 帧率与计划一致。 +- 时长等于各场景时长之和,允许一个帧间隔误差。 +- 视频完整解码,无黑帧、冻结或截断。 + +抽取: + +- 首帧。 +- 每个图层进入前一帧、落位后一帧。 +- 每幕中点。 +- 最后一帧。 +- contact sheet。 + +视觉检查: + +- 第一帧是否确实接近空场。 +- 元素是否逐件进入,而不是整图晃动。 +- 切边、白色 keyline 和阴影是否稳定。 +- 最终构图是否与获批静帧一致。 +- 标签、字幕、数字人和平台 UI 是否互相避让。 +- 每幕是否只有一个核心创意。 + +## 来源一致性 + +`render_assembly.py` 会在输出旁写入 `render-manifest.json`,包含计划和成片 SHA-256。制作说明中的来源字段必须与 manifest 一致。 + +以下情况不得写“完成”: + +- 静帧未获确认。 +- 计划校验失败。 +- 只做了源码或预览,未生成目标 MP4。 +- 未做媒体探针或关键帧视觉检查。 +- 实际提供方不明。 + +暂时不能渲染时,写 `pending_render`。只完成条带预览时,写 `preview_bands`。 diff --git a/skills/rn-editorial-collage-motion/references/schemas.md b/skills/rn-editorial-collage-motion/references/schemas.md new file mode 100644 index 0000000..807a03e --- /dev/null +++ b/skills/rn-editorial-collage-motion/references/schemas.md @@ -0,0 +1,90 @@ +# Collage Schemas + +## 目录 + +1. 视觉规范 +2. 组装计划 +3. 图层模式 +4. 条带模式 +5. 文件布局 + +## 1. 视觉规范 + +以 `assets/templates/collage-spec.json` 为起点。必填字段: + +- `medium`、`craft_style`、`aspect_ratio`、`style_signature` +- `color_field.background_hex`、`evenness`、`paper_grain` +- `elements[]` 的 `id`、`what`、`role`、`halftone`、`cut_edge`、`drop_shadow`、`color_treatment`、`placement` +- `palette_hex` +- `composition.layout`、`depth_layers`、`negative_space`、`balance`、`reserved_areas` +- `idea` +- `label.present`、`content`、`font_character`、`weight`、`placement`、`treatment`、`editable` +- `mood`、`references_era`、`negative_prompt` + +每个场景的规范必须自包含。不要写“同上一幕”。 + +## 2. 组装计划 + +以 `assets/templates/assembly-plan.json` 为起点。 + +顶层字段: + +- `version`:当前为 `1`。 +- `canvas.width`、`height`、`fps`。 +- `provenance.actual_still_provider`:真实静帧来源。默认 Codex 内置生图写 `codex-image-gen`;用户提供写 `user-supplied`。 +- `provenance.actual_motion_provider`:本脚本固定输出 `local-ffmpeg`。 +- `provenance.external_uploads`:布尔值。 +- `scenes[]`:按播放顺序排列。 + +场景公共字段: + +- `id`:唯一、文件安全的场景名。 +- `duration_s`:大于 0。 +- `background_hex`:`#RRGGBB`。 +- `mode`:`layered` 或 `bands`。 + +## 3. 图层模式 + +`layered` 是正式模式。每个 `pieces[]` 对象包含: + +- `source`:项目目录内的透明 PNG 相对路径。 +- `x`、`y`:最终左上角坐标。 +- `width`、`height`:可选;同时提供时缩放图层。 +- `entry.from`:`left`、`right`、`top`、`bottom`。 +- `entry.start_s`、`end_s`:进入区间。 +- `entry.distance_px`:可选;默认足以让图层起始时位于画外。 + +列表顺序就是合成层级。先写底层,后写顶层。 + +## 4. 条带模式 + +`bands` 只用于预览或明确接受的简化版本: + +- `still`:完整静帧相对路径。 +- `bands`:2 到 8。 +- `entry_s`:每条进入时长。 +- `stagger_s`:相邻条带的启动间隔。 +- `first_from`:第一条从 `left` 或 `right` 进入,后续交替。 + +条带模式不会产生真实的逐元素组装,制作说明必须写明 `preview_bands`。 + +## 5. 文件布局 + +推荐工程结构: + +```text +project/ +├── collage-spec.json +├── assembly-plan.json +├── assets/ +│ ├── references/ +│ ├── stills/ +│ └── pieces/ +├── renders/ +│ ├── scene-clips/ +│ ├── collage-assembly.mp4 +│ └── render-manifest.json +└── qc/ +``` + +所有中间工程放 `_工程区/动效项目/`。最终视频继续服从内容系统的已制作归档规则。 diff --git a/skills/rn-editorial-collage-motion/references/visual-contract.md b/skills/rn-editorial-collage-motion/references/visual-contract.md new file mode 100644 index 0000000..a5dee09 --- /dev/null +++ b/skills/rn-editorial-collage-motion/references/visual-contract.md @@ -0,0 +1,90 @@ +# Editorial Collage Visual Contract + +## 目录 + +1. 核心视觉 +2. 视觉参数 +3. 场景设计 +4. 动画语法 +5. 排版和安全区 +6. 禁止项 + +## 1. 核心视觉 + +默认使用 editorial halftone collage: + +- 单一、平坦、饱和度明确的纯色色场。 +- 黑白半色调剪纸主体。 +- 清晰的机器切边或轻微手工切边。 +- 细白色纸张 keyline。 +- 低透明度、方向一致的柔和投影。 +- 一幕一个视觉隐喻或动作结论。 +- 从空背景开始,元素逐件进入并卡入最终位置。 + +这是一种视觉合同,不代表 Arcads、Nano Banana、Seedance 或 Kling 的实际调用。 + +## 2. 视觉参数 + +### 色场 + +- `background_hex`:记录准确十六进制颜色。 +- `evenness`:默认完全平坦,无渐变和暗角。 +- `paper_grain`:可选细颗粒纸纹,透明度应克制。 + +### 半色调 + +- 粗网点:约 25 到 45 lpi,强调大胆和复古。 +- 细网点:约 65 到 85 lpi,强调编辑感和克制。 +- 默认使用黑白圆点网屏。 +- 同一组场景保持密度、角度和黑白关系一致。 + +### 切边和阴影 + +- 正式默认:清晰切边,2 到 8px 白色 keyline。 +- 竖屏 1080 宽画面建议 5 到 8px keyline。 +- 阴影方向在同一组中固定,常用右下偏移。 +- 阴影不应像厚重 3D 悬浮卡片。 + +## 3. 场景设计 + +每幕先写一句 `idea`,再选元素。一个场景最多有一个主视觉判断,辅助元素只解释主判断。 + +推荐层级: + +1. 纯色色场。 +2. 辅助卡片、箭头或几何纸片。 +3. 主体剪纸。 +4. 关键强调物。 +5. 可编辑文字或标签。 + +保留足够负空间,让起始空场和组装轨迹可读。数字人默认占左下时,把左下四分之一区域写入 `reserved_areas`。 + +## 4. 动画语法 + +正式动画遵循: + +1. 首帧只显示色场或极少固定纹理。 +2. 辅助层先进入,建立方向。 +3. 主体从另一侧或上下边缘进入。 +4. 强调物最后落位。 +5. 文字在主构图稳定后出现,或作为独立纸片最后进入。 +6. 完整构图至少停留 0.6 秒;需要阅读时更长。 + +入口动作使用明确位移和短促落位。可以有一次轻微 overshoot,但不要持续摆动。跨幕转场服务于剪纸材质,例如纸张撕裂、半色调圆形 iris、纸卡翻页。每个边界只使用一个主转场。 + +## 5. 排版和安全区 + +- 标签建议 2 到 8 个汉字或 2 到 4 个英文词。 +- 中文文字优先作为可编辑排版层,避免生成模型乱码。 +- 竖屏默认安全区:上 120px、左右 72px、下 180px,再叠加平台和数字人避让区。 +- 横屏默认安全区:上下 72px、左右 96px。 +- 文字不得压住主体关键动作或字幕。 + +## 6. 禁止项 + +- 不用镜头晃动、呼吸缩放、随机漂移替代逐件组装。 +- 不把完整静帧整体推入当作逐元素动画。 +- 不使用渐变、发光、玻璃拟态或厚重 3D 阴影破坏纸张语义。 +- 不在同一组中任意改变半色调密度、切边和阴影方向。 +- 不堆叠多个核心创意。 +- 不把本地兼容渲染标记为第三方模型原生生成。 diff --git a/skills/rn-editorial-collage-motion/scripts/render_assembly.py b/skills/rn-editorial-collage-motion/scripts/render_assembly.py new file mode 100755 index 0000000..925bfad --- /dev/null +++ b/skills/rn-editorial-collage-motion/scripts/render_assembly.py @@ -0,0 +1,210 @@ +#!/usr/bin/env python3 +import argparse +import hashlib +import json +import re +import shutil +import subprocess +from datetime import datetime, timezone +from pathlib import Path + + +HEX = re.compile(r"^#[0-9A-Fa-f]{6}$") + + +def run(command): + subprocess.run(command, check=True) + + +def sha256(path): + digest = hashlib.sha256() + with path.open("rb") as handle: + for chunk in iter(lambda: handle.read(1024 * 1024), b""): + digest.update(chunk) + return digest.hexdigest() + + +def inside(project, relative): + if not isinstance(relative, str) or not relative: + raise ValueError("asset path must be a non-empty string") + path = (project / relative).resolve() + try: + path.relative_to(project) + except ValueError as exc: + raise ValueError(f"asset escapes project directory: {relative}") from exc + if not path.is_file(): + raise FileNotFoundError(path) + return path + + +def motion_expr(final, before, start, end): + moving = f"{before}+(t-{start:.6f})/({end-start:.6f})*({final-before})" + return f"if(lt(t,{start:.6f}),{before},if(lt(t,{end:.6f}),{moving},{final}))" + + +def encode_args(fps): + return [ + "-r", str(fps), "-an", "-c:v", "libx264", "-preset", "fast", + "-crf", "18", "-pix_fmt", "yuv420p", "-movflags", "+faststart", + ] + + +def render_layered(project, scene, canvas, output): + width, height, fps = canvas["width"], canvas["height"], canvas["fps"] + duration = float(scene["duration_s"]) + color = scene["background_hex"] + if not HEX.fullmatch(color): + raise ValueError(f"invalid background color: {color}") + pieces = scene.get("pieces") or [] + if not pieces: + raise ValueError(f"{scene['id']} has no pieces") + command = [ + "ffmpeg", "-y", "-hide_banner", "-loglevel", "error", + "-f", "lavfi", "-i", f"color=c={color}:s={width}x{height}:r={fps}:d={duration}", + ] + for piece in pieces: + source = inside(project, piece["source"]) + command += ["-loop", "1", "-framerate", str(fps), "-t", str(duration), "-i", str(source)] + filters = ["[0:v]format=rgba[base]"] + previous = "base" + for index, piece in enumerate(pieces, start=1): + source_label = f"p{index}" + if "width" in piece and "height" in piece: + filters.append(f"[{index}:v]scale={int(piece['width'])}:{int(piece['height'])},format=rgba[{source_label}]") + piece_width = int(piece["width"]) + piece_height = int(piece["height"]) + else: + filters.append(f"[{index}:v]format=rgba[{source_label}]") + piece_width = width + piece_height = height + x = float(piece["x"]) + y = float(piece["y"]) + entry = piece["entry"] + start = float(entry["start_s"]) + end = float(entry["end_s"]) + direction = entry["from"] + default_distance = width + piece_width if direction in {"left", "right"} else height + piece_height + distance = float(entry.get("distance_px", default_distance)) + if direction == "left": + ox, oy = motion_expr(x, x - distance, start, end), f"{y:.3f}" + elif direction == "right": + ox, oy = motion_expr(x, x + distance, start, end), f"{y:.3f}" + elif direction == "top": + ox, oy = f"{x:.3f}", motion_expr(y, y - distance, start, end) + elif direction == "bottom": + ox, oy = f"{x:.3f}", motion_expr(y, y + distance, start, end) + else: + raise ValueError(f"invalid entry direction: {direction}") + out = f"v{index}" + filters.append(f"[{previous}][{source_label}]overlay=x='{ox}':y='{oy}':eval=frame:format=auto[{out}]") + previous = out + filters.append(f"[{previous}]format=yuv420p[out]") + command += ["-filter_complex", ";".join(filters), "-map", "[out]", "-t", f"{duration:.6f}"] + command += encode_args(fps) + [str(output)] + run(command) + + +def render_bands(project, scene, canvas, output): + width, height, fps = canvas["width"], canvas["height"], canvas["fps"] + duration = float(scene["duration_s"]) + color = scene["background_hex"] + still = inside(project, scene["still"]) + bands = int(scene.get("bands", 3)) + entry_s = float(scene.get("entry_s", 0.72)) + stagger_s = float(scene.get("stagger_s", 0.18)) + first_from = scene.get("first_from", "left") + command = [ + "ffmpeg", "-y", "-hide_banner", "-loglevel", "error", + "-f", "lavfi", "-i", f"color=c={color}:s={width}x{height}:r={fps}:d={duration}", + "-loop", "1", "-framerate", str(fps), "-t", str(duration), "-i", str(still), + ] + labels = "".join(f"[s{i}]" for i in range(bands)) + filters = [ + f"[0:v]format=rgba[base]", + f"[1:v]scale={width}:{height}:force_original_aspect_ratio=decrease,pad={width}:{height}:(ow-iw)/2:(oh-ih)/2,format=rgba,split={bands}{labels}", + ] + previous = "base" + y = 0 + for index in range(bands): + band_height = height // bands if index < bands - 1 else height - y + filters.append(f"[s{index}]crop={width}:{band_height}:0:{y}[b{index}]") + start = index * stagger_s + end = start + entry_s + from_left = (index % 2 == 0) == (first_from == "left") + before = -width if from_left else width + ox = motion_expr(0, before, start, end) + out = f"v{index}" + filters.append(f"[{previous}][b{index}]overlay=x='{ox}':y={y}:eval=frame:format=auto[{out}]") + previous = out + y += band_height + filters.append(f"[{previous}]format=yuv420p[out]") + command += ["-filter_complex", ";".join(filters), "-map", "[out]", "-t", f"{duration:.6f}"] + command += encode_args(fps) + [str(output)] + run(command) + + +def main(): + parser = argparse.ArgumentParser(description="Render deterministic editorial collage assembly motion") + parser.add_argument("--project", required=True, type=Path) + parser.add_argument("--plan", required=True, type=Path) + parser.add_argument("--output", required=True, type=Path) + args = parser.parse_args() + if not shutil.which("ffmpeg") or not shutil.which("ffprobe"): + raise SystemExit("ffmpeg and ffprobe are required") + project = args.project.resolve() + plan_path = args.plan.resolve() + output = args.output.resolve() + plan = json.loads(plan_path.read_text(encoding="utf-8")) + if plan.get("version") != 1: + raise SystemExit("unsupported plan version") + canvas = plan["canvas"] + scenes = plan.get("scenes") or [] + if not scenes: + raise SystemExit("plan has no scenes") + scene_dir = output.parent / "scene-clips" + scene_dir.mkdir(parents=True, exist_ok=True) + clips = [] + for scene in scenes: + clip = scene_dir / f"{scene['id']}.mp4" + if scene.get("mode") == "layered": + render_layered(project, scene, canvas, clip) + elif scene.get("mode") == "bands": + render_bands(project, scene, canvas, clip) + else: + raise SystemExit(f"unknown mode for {scene.get('id')}: {scene.get('mode')}") + clips.append(clip) + output.parent.mkdir(parents=True, exist_ok=True) + concat = scene_dir / "concat.txt" + concat.write_text("".join(f"file '{clip.as_posix()}'\n" for clip in clips), encoding="utf-8") + run([ + "ffmpeg", "-y", "-hide_banner", "-loglevel", "error", "-f", "concat", "-safe", "0", + "-i", str(concat), "-an", "-c:v", "libx264", "-preset", "fast", "-crf", "18", + "-pix_fmt", "yuv420p", "-movflags", "+faststart", str(output), + ]) + probe = subprocess.run([ + "ffprobe", "-v", "error", "-show_entries", "format=duration,size:stream=codec_name,width,height,r_frame_rate,pix_fmt", + "-of", "json", str(output), + ], check=True, capture_output=True, text=True) + manifest = { + "generated_at": datetime.now(timezone.utc).isoformat(), + "renderer": "local-ffmpeg", + "actual_still_provider": plan.get("provenance", {}).get("actual_still_provider", "unknown"), + "actual_motion_provider": "local-ffmpeg", + "external_uploads": bool(plan.get("provenance", {}).get("external_uploads", False)), + "compatible_render": bool(plan.get("provenance", {}).get("compatible_render", True)), + "compatible_with": plan.get("provenance", {}).get("compatible_with", "rn-editorial-collage-motion visual contract"), + "plan": str(plan_path), + "plan_sha256": sha256(plan_path), + "output": str(output), + "output_sha256": sha256(output), + "scene_modes": {scene["id"]: scene["mode"] for scene in scenes}, + "probe": json.loads(probe.stdout), + } + manifest_path = output.parent / "render-manifest.json" + manifest_path.write_text(json.dumps(manifest, ensure_ascii=False, indent=2), encoding="utf-8") + print(output) + print(manifest_path) + + +if __name__ == "__main__": + main() diff --git a/skills/rn-editorial-collage-motion/scripts/validate_collage.py b/skills/rn-editorial-collage-motion/scripts/validate_collage.py new file mode 100755 index 0000000..3ed81bc --- /dev/null +++ b/skills/rn-editorial-collage-motion/scripts/validate_collage.py @@ -0,0 +1,248 @@ +#!/usr/bin/env python3 +import argparse +import json +import re +import shutil +import subprocess +import sys +from pathlib import Path + + +HEX = re.compile(r"^#[0-9A-Fa-f]{6}$") +SID = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]*$") + + +def load_json(path: Path): + try: + return json.loads(path.read_text(encoding="utf-8")) + except FileNotFoundError: + raise ValueError(f"missing file: {path}") + except json.JSONDecodeError as exc: + raise ValueError(f"invalid JSON in {path}: {exc}") + + +def require(obj, path, errors): + current = obj + for key in path.split("."): + if not isinstance(current, dict) or key not in current: + errors.append(f"missing field: {path}") + return None + current = current[key] + return current + + +def validate_spec(spec, errors): + for field in ( + "medium", "craft_style", "aspect_ratio", "style_signature", + "color_field.background_hex", "color_field.evenness", "color_field.paper_grain", + "palette_hex", "composition.layout", "composition.depth_layers", + "composition.negative_space", "composition.balance", "composition.reserved_areas", + "idea", "label.present", "label.content", "label.font_character", + "label.weight", "label.placement", "label.treatment", "label.editable", + "mood", "references_era", "negative_prompt", + ): + require(spec, field, errors) + background = require(spec, "color_field.background_hex", errors) + if background is not None and not HEX.fullmatch(str(background)): + errors.append("color_field.background_hex must be #RRGGBB") + palette = spec.get("palette_hex", []) + if not isinstance(palette, list) or not palette: + errors.append("palette_hex must be a non-empty list") + elif any(not HEX.fullmatch(str(color)) for color in palette): + errors.append("every palette_hex value must be #RRGGBB") + elements = spec.get("elements") + if not isinstance(elements, list) or not elements: + errors.append("elements must be a non-empty list") + else: + required = {"id", "what", "role", "halftone", "cut_edge", "drop_shadow", "color_treatment", "placement"} + for index, element in enumerate(elements): + if not isinstance(element, dict): + errors.append(f"elements[{index}] must be an object") + continue + missing = sorted(required - element.keys()) + if missing: + errors.append(f"elements[{index}] missing: {', '.join(missing)}") + + +def safe_asset(project: Path, value: str, label: str, errors): + candidate = (project / value).resolve() + try: + candidate.relative_to(project) + except ValueError: + errors.append(f"{label} escapes project directory: {value}") + return None + if not candidate.is_file(): + errors.append(f"{label} not found: {candidate}") + return None + return candidate + + +def validate_layer_alpha(path: Path, label: str, errors): + if path.suffix.lower() != ".png": + errors.append(f"{label} must be a PNG with transparency") + return + if not shutil.which("ffmpeg"): + errors.append("ffmpeg is required to inspect layered PNG alpha") + return + result = subprocess.run( + [ + "ffmpeg", "-hide_banner", "-loglevel", "error", "-i", str(path), + "-vf", "alphaextract,signalstats,metadata=print:file=-", + "-frames:v", "1", "-f", "null", "-", + ], + capture_output=True, + text=True, + ) + output = result.stdout + result.stderr + if result.returncode != 0: + errors.append(f"{label} must contain an alpha channel") + return + minimum = re.search(r"lavfi\.signalstats\.YMIN=(\d+)", output) + maximum = re.search(r"lavfi\.signalstats\.YMAX=(\d+)", output) + if not minimum or not maximum: + errors.append(f"could not inspect alpha range for {label}") + return + alpha_min = int(minimum.group(1)) + alpha_max = int(maximum.group(1)) + if alpha_max == 0: + errors.append(f"{label} is fully transparent") + elif alpha_min == 255: + errors.append(f"{label} is fully opaque; layered pieces need transparent pixels") + + +def validate_plan(plan, project, errors): + if plan.get("version") != 1: + errors.append("plan version must be 1") + canvas = plan.get("canvas") + if not isinstance(canvas, dict): + errors.append("canvas must be an object") + else: + for key in ("width", "height", "fps"): + value = canvas.get(key) + if not isinstance(value, int) or value <= 0: + errors.append(f"canvas.{key} must be a positive integer") + provenance = plan.get("provenance") + if not isinstance(provenance, dict): + errors.append("provenance must be an object") + else: + for key in ("actual_still_provider", "actual_motion_provider", "external_uploads"): + if key not in provenance: + errors.append(f"provenance.{key} is required") + if provenance.get("actual_motion_provider") != "local-ffmpeg": + errors.append("this renderer requires provenance.actual_motion_provider=local-ffmpeg") + scenes = plan.get("scenes") + if not isinstance(scenes, list) or not scenes: + errors.append("scenes must be a non-empty list") + return + ids = set() + for index, scene in enumerate(scenes): + prefix = f"scenes[{index}]" + if not isinstance(scene, dict): + errors.append(f"{prefix} must be an object") + continue + scene_id = scene.get("id") + if not isinstance(scene_id, str) or not SID.fullmatch(scene_id): + errors.append(f"{prefix}.id must be file-safe") + elif scene_id in ids: + errors.append(f"duplicate scene id: {scene_id}") + else: + ids.add(scene_id) + duration = scene.get("duration_s") + if not isinstance(duration, (int, float)) or duration <= 0: + errors.append(f"{prefix}.duration_s must be positive") + background = scene.get("background_hex") + if not isinstance(background, str) or not HEX.fullmatch(background): + errors.append(f"{prefix}.background_hex must be #RRGGBB") + mode = scene.get("mode") + if mode == "layered": + pieces = scene.get("pieces") + if not isinstance(pieces, list) or not pieces: + errors.append(f"{prefix}.pieces must be a non-empty list") + continue + previous_start = -1.0 + for piece_index, piece in enumerate(pieces): + pp = f"{prefix}.pieces[{piece_index}]" + if not isinstance(piece, dict): + errors.append(f"{pp} must be an object") + continue + source = piece.get("source") + if not isinstance(source, str) or not source: + errors.append(f"{pp}.source must be a project-relative PNG path") + elif project: + source_path = safe_asset(project, source, f"{pp}.source", errors) + if source_path: + validate_layer_alpha(source_path, f"{pp}.source", errors) + for axis in ("x", "y"): + if not isinstance(piece.get(axis), (int, float)): + errors.append(f"{pp}.{axis} must be numeric") + entry = piece.get("entry") + if not isinstance(entry, dict): + errors.append(f"{pp}.entry must be an object") + continue + if entry.get("from") not in {"left", "right", "top", "bottom"}: + errors.append(f"{pp}.entry.from is invalid") + start = entry.get("start_s") + end = entry.get("end_s") + if not isinstance(start, (int, float)) or not isinstance(end, (int, float)) or not 0 <= start < end: + errors.append(f"{pp}.entry requires 0 <= start_s < end_s") + elif isinstance(duration, (int, float)) and end > duration: + errors.append(f"{pp}.entry.end_s exceeds scene duration") + if isinstance(start, (int, float)) and start < previous_start: + errors.append(f"{pp}.entry.start_s must not go backwards") + if isinstance(start, (int, float)): + previous_start = start + has_width = "width" in piece + has_height = "height" in piece + if has_width != has_height: + errors.append(f"{pp} must provide both width and height or neither") + elif has_width: + if not isinstance(piece["width"], (int, float)) or piece["width"] <= 0: + errors.append(f"{pp}.width must be positive") + if not isinstance(piece["height"], (int, float)) or piece["height"] <= 0: + errors.append(f"{pp}.height must be positive") + if "distance_px" in entry and ( + not isinstance(entry["distance_px"], (int, float)) or entry["distance_px"] <= 0 + ): + errors.append(f"{pp}.entry.distance_px must be positive") + elif mode == "bands": + still = scene.get("still") + if not isinstance(still, str) or not still: + errors.append(f"{prefix}.still must be a project-relative image path") + elif project: + safe_asset(project, still, f"{prefix}.still", errors) + bands = scene.get("bands", 3) + if not isinstance(bands, int) or not 2 <= bands <= 8: + errors.append(f"{prefix}.bands must be an integer from 2 to 8") + if scene.get("first_from", "left") not in {"left", "right"}: + errors.append(f"{prefix}.first_from must be left or right") + else: + errors.append(f"{prefix}.mode must be layered or bands") + + +def main(): + parser = argparse.ArgumentParser(description="Validate editorial collage specs and assembly plans") + parser.add_argument("--spec", type=Path) + parser.add_argument("--plan", type=Path) + parser.add_argument("--project", type=Path) + args = parser.parse_args() + if not args.spec and not args.plan: + parser.error("provide --spec, --plan, or both") + errors = [] + try: + if args.spec: + validate_spec(load_json(args.spec.resolve()), errors) + if args.plan: + project = args.project.resolve() if args.project else None + validate_plan(load_json(args.plan.resolve()), project, errors) + except ValueError as exc: + errors.append(str(exc)) + if errors: + for error in errors: + print(f"ERROR: {error}", file=sys.stderr) + return 1 + print("PASS") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/skills/rn-ian-xiaohei-cat-illustrations/SKILL.md b/skills/rn-ian-xiaohei-cat-illustrations/SKILL.md new file mode 100644 index 0000000..3d1f1ef --- /dev/null +++ b/skills/rn-ian-xiaohei-cat-illustrations/SKILL.md @@ -0,0 +1,120 @@ +--- +name: rn-ian-xiaohei-cat-illustrations +description: 生成 Ian 风格的小黑猫中文正文配图。用于用户要求为中文文章、帖子、博客、Notion 文档、工作流文档、方法论、流程、结构、状态、隐喻或观点生成“怪诞”“小黑猫”“黑猫”“手绘”“正文配图”“文章插图”“配图建议”“shot list”“去标题/改图”等任务;默认使用小黑猫 IP、纯白手绘、少量红橙蓝批注、简洁清爽但天马行空的视觉风格。 +--- + +# Ian 小黑猫怪诞正文配图 + +## 核心定位 + +为中文文章设计和生成 16:9 横版正文配图。目标不是做商业插画、PPT 信息图或可爱卡通,而是把文章里的关键判断、流程、结构、状态或隐喻,变成一张清爽、怪诞、有创意、可读但不说明书的手绘解释图。 + +默认视觉 IP 是“小黑猫”:旧版小黑的猫形替换版,大而略歪的黑色猫头、较小的黑色身体、两只占脸面积很大的白色椭圆眼、同向偏移的黑色瞳孔、尖耳、短粗手脚、空表情,认真做一件荒诞但成立的事。小黑猫必须参与画面的核心动作,不能只是站在旁边当装饰。 + +小黑猫不是普通黑猫,也不是升级成复杂新卡通。默认复杂度要接近原小黑素材:一只小黑猫、一个核心动作、1-2 个主要物件、3-5 个短标注、大量留白。但角色形象必须优先匹配过往视频里的原始小黑猫:大头小身、巨大白色椭圆眼、黑瞳同向偏移、短粗肢体、无嘴无胡须、死认真、略怪诞。压低的是场景复杂度,不是角色识别度。 + +## 先读这些参考 + +按任务需要读取,不要一次塞满上下文: + +- `references/style-dna.md`:风格 DNA、颜色、文字、禁忌。 +- `references/xiaohei-cat-ip.md`:小黑猫 IP 的形象、性格、动作库和禁忌。 +- `references/composition-patterns.md`:结构类型、原创隐喻方法和反复刻规则。 +- `references/prompt-template.md`:单张生图提示词模板。 +- `references/qa-checklist.md`:生成后检查和迭代规则。 +- `assets/ip-reference/00-source-safety-audit-cat.png`:从旧视频原图裁出的权威角色参考。每次生图都必须把它作为第一张角色参考图传给 `image_gen`;只锁定角色,不复刻清单、按钮或机器。 +- `assets/ip-reference/01-approved-simple-funnel-cat.png`:用户确认过的低复杂度构图参考;只校准场景密度和留白,不作为角色外形真源,不复刻漏斗构图。 +- `assets/examples/15-fact-vs-guess-cat.png`、`16-content-handoff-door-cat.png`:跨场景身份验证通过的正向样例;只校准角色稳定性与简洁度,不复刻秤或门。 +- `assets/examples/`:用原小黑素材校准低复杂度、线条密度、留白和动作参与方式;只把角色替换成小黑猫。不要照抄这些案例的构图、物件或标注。 + +## 工作流 + +### 1. 消化正文 + +先读用户给的正文、链接、Notion 页面、Markdown 文件或截图内容。提炼: + +- 核心观点是什么 +- 哪些段落承担认知转折 +- 哪些内容适合用图解释 +- 哪些地方只适合文字,不需要图 + +不要平均配图。优先选择“认知锚点”,例如:核心判断、两个断点、输入输出闭环、分流、前后对比、一鱼多吃、承接路径、常见坑、角色状态变化。 + +### 2. 先出配图策略 + +如果用户只是说“分析怎么配图 / 思考哪些地方需要配图”,先给 shot list。每张图写清楚: + +- 放在哪个段落后 +- 图的主题 +- 核心意思 +- 结构类型 +- 小黑猫在图里做什么 +- 建议元素 +- 建议中文标注词 + +默认 4-8 张。文章很短时 1-3 张;长文也不要轻易超过 9 张。够用就好,避免把正文做成画册。 + +### 3. 单张生成 + +如果用户明确要求“生成 / 输出 / 做图 / 帮我生成”,不要停下来等确认;用内置 `image_gen` 每张单独生成。不要把多张图拼在一张里。 + +每张图只讲一个核心结构。提示词必须包含: + +- 16:9 横版中文正文配图 +- 纯白背景 +- 黑色手绘线稿 +- 少量红色/橙色/蓝色中文手写批注 +- 大量留白 +- 小黑猫作为核心动作主体 +- 把 `assets/ip-reference/00-source-safety-audit-cat.png` 作为角色参考图输入 +- 小黑猫必须有大而略歪的猫头、较小身体、巨大白色椭圆眼、同向偏移黑瞳、短粗手脚、无嘴无胡须、死认真气质 +- 禁止 PPT、商业插画、幼稚可爱、复杂架构、复杂机器、多屏面板、左上角类型标题 + +不要复刻过往案例。案例只提供风格密度和小黑猫参与方式,不能直接复用“传送带断点 / 小黑猫拉线 / 素材鱼 / 盖章工具箱 / 常见坑路径”等已有构图,除非用户明确要求复刻某张图。每次都要从当前文章重新发明一个奇怪但成立的隐喻。 + +### 4. 检查与迭代 + +生成后检查 `references/qa-checklist.md`。如果出现以下问题,优先重生成或局部编辑: + +- 小黑猫只是装饰 +- 小黑猫与权威角色参考的加权相似度低于 90% +- 小黑猫像普通黑猫,缺少大头小身、巨大白眼、偏移瞳孔和怪诞气质 +- 画面太满 +- 小黑猫或场景过度复杂,像完整视频页 +- 太像流程图/PPT +- 中文太多或错字严重 +- 左上角出现“常见坑/流程图/系统架构图”等标题 +- 画风太可爱、幼稚、死板 +- 背景不是干净白底 + +### 5. 保存交付 + +如果用户在 workspace 内工作,把最终图复制到: + +```text +assets/-illustrations/ +``` + +按顺序命名: + +```text +01-topic-name.png +02-topic-name.png +``` + +保留原始生成文件,不要覆盖已有资产,除非用户明确要求替换。 + +## 输出口径 + +生成前的策略输出要短而准。生成后的交付要包含: + +- 生成了几张 +- 每张图的用途 +- 保存路径 +- 哪些图最稳,哪些图是可选 + +不要长篇解释风格理论;让图自己说话。 + +## 来源与许可 + +本 Skill 基于 Ian(`helloianneo`)的 `ian-xiaohei-illustrations` 改编,将原版“小黑”角色替换并扩展为本地“小黑猫”IP,同时增加权威角色参考、身份一致性评分和更严格的场景复杂度约束。再分发时必须保留 `references/origin-and-license.md` 中的来源、修改说明和 MIT 许可证。 diff --git a/skills/rn-ian-xiaohei-cat-illustrations/agents/openai.yaml b/skills/rn-ian-xiaohei-cat-illustrations/agents/openai.yaml new file mode 100644 index 0000000..4e5ce49 --- /dev/null +++ b/skills/rn-ian-xiaohei-cat-illustrations/agents/openai.yaml @@ -0,0 +1,6 @@ +interface: + display_name: "Ian 小黑猫配图" + short_description: "为中文文章生成怪诞清爽、有小黑猫IP的正文配图资产" + default_prompt: "Use $rn-ian-xiaohei-cat-illustrations to 为这篇中文文章设计并生成几张小黑猫怪诞正文配图。" +policy: + allow_implicit_invocation: true diff --git a/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/01-two-breakpoints.png b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/01-two-breakpoints.png new file mode 100644 index 0000000..44c197d Binary files /dev/null and b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/01-two-breakpoints.png differ diff --git a/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/02-minimum-loop.png b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/02-minimum-loop.png new file mode 100644 index 0000000..2629a08 Binary files /dev/null and b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/02-minimum-loop.png differ diff --git a/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/03-sort-by-purpose.png b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/03-sort-by-purpose.png new file mode 100644 index 0000000..80b2989 Binary files /dev/null and b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/03-sort-by-purpose.png differ diff --git a/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/04-one-fish-many-uses.png b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/04-one-fish-many-uses.png new file mode 100644 index 0000000..b87e74a Binary files /dev/null and b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/04-one-fish-many-uses.png differ diff --git a/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/05-handoff-path.png b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/05-handoff-path.png new file mode 100644 index 0000000..166b9c9 Binary files /dev/null and b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/05-handoff-path.png differ diff --git a/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/06-three-sources.png b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/06-three-sources.png new file mode 100644 index 0000000..e6b51a7 Binary files /dev/null and b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/06-three-sources.png differ diff --git a/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/07-three-content-jobs.png b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/07-three-content-jobs.png new file mode 100644 index 0000000..5ffd89f Binary files /dev/null and b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/07-three-content-jobs.png differ diff --git a/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/08-handoff-copy-toolbox.png b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/08-handoff-copy-toolbox.png new file mode 100644 index 0000000..1c0ad2c Binary files /dev/null and b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/08-handoff-copy-toolbox.png differ diff --git a/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/09-common-pits-no-title.png b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/09-common-pits-no-title.png new file mode 100644 index 0000000..6b2fcb8 Binary files /dev/null and b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/09-common-pits-no-title.png differ diff --git a/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/10-information-well.png b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/10-information-well.png new file mode 100644 index 0000000..f498931 Binary files /dev/null and b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/10-information-well.png differ diff --git a/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/11-idea-press.png b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/11-idea-press.png new file mode 100644 index 0000000..5d12483 Binary files /dev/null and b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/11-idea-press.png differ diff --git a/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/12-content-fermentation.png b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/12-content-fermentation.png new file mode 100644 index 0000000..c056506 Binary files /dev/null and b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/12-content-fermentation.png differ diff --git a/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/13-system-bearing.png b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/13-system-bearing.png new file mode 100644 index 0000000..efcae9e Binary files /dev/null and b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/13-system-bearing.png differ diff --git a/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/14-trust-bridge.png b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/14-trust-bridge.png new file mode 100644 index 0000000..18d3556 Binary files /dev/null and b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/14-trust-bridge.png differ diff --git a/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/15-fact-vs-guess-cat.png b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/15-fact-vs-guess-cat.png new file mode 100644 index 0000000..7e03cc4 Binary files /dev/null and b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/15-fact-vs-guess-cat.png differ diff --git a/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/16-content-handoff-door-cat.png b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/16-content-handoff-door-cat.png new file mode 100644 index 0000000..11aece2 Binary files /dev/null and b/skills/rn-ian-xiaohei-cat-illustrations/assets/examples/16-content-handoff-door-cat.png differ diff --git a/skills/rn-ian-xiaohei-cat-illustrations/assets/ip-reference/00-source-safety-audit-cat.png b/skills/rn-ian-xiaohei-cat-illustrations/assets/ip-reference/00-source-safety-audit-cat.png new file mode 100644 index 0000000..88d3e57 Binary files /dev/null and b/skills/rn-ian-xiaohei-cat-illustrations/assets/ip-reference/00-source-safety-audit-cat.png differ diff --git a/skills/rn-ian-xiaohei-cat-illustrations/assets/ip-reference/01-approved-simple-funnel-cat.png b/skills/rn-ian-xiaohei-cat-illustrations/assets/ip-reference/01-approved-simple-funnel-cat.png new file mode 100644 index 0000000..55f3ba3 Binary files /dev/null and b/skills/rn-ian-xiaohei-cat-illustrations/assets/ip-reference/01-approved-simple-funnel-cat.png differ diff --git a/skills/rn-ian-xiaohei-cat-illustrations/references/composition-patterns.md b/skills/rn-ian-xiaohei-cat-illustrations/references/composition-patterns.md new file mode 100644 index 0000000..219ebe3 --- /dev/null +++ b/skills/rn-ian-xiaohei-cat-illustrations/references/composition-patterns.md @@ -0,0 +1,101 @@ +# 构图模式与原创规则 + +## 基础结构类型 + +选择一种结构即可,不要混太多。 + +### Workflow 流程 + +适合:输入 -> 处理 -> 输出,内容生产,AI 工作流,自动化链路。 + +画法:左侧输入,中间小黑猫或一个低科技小装置处理,右侧输出,橙色箭头表达主流向。不要默认画复杂机器。 + +### 系统局部 + +适合:信息来源、过滤器、数据库、渲染器、agent 系统局部。 + +画法:只画 2-4 个核心模块,小黑猫参与其中一个关键动作。 + +### 前后对比 + +适合:混乱/有序,手动/自动,分散/收拢,焦虑/稳定。 + +画法:左混乱,右稳定,中间橙色箭头。角色可以更夸张。 + +### 角色状态 + +适合:用户痛点、创作者状态、工具太多、信息焦虑、卡住到跑起来。 + +画法:2-4 个小状态,每个状态一个短标注。 + +### 概念隐喻 + +适合:内容工厂、信息仓库、脑内黑盒、工作流机器、自动日报。 + +画法:一个简单怪物件,少量输入,一个输出。要有记忆点,但不要变成复杂机器页。 + +### 方法分层 + +适合:方法论框架、系统层级、能力栈、内容系统分层。 + +画法:一层层盒子,不要正式金字塔;小黑猫在旁边搬砖或搭建。 + +### 地图路线 + +适合:从想法到上线、用户路径、内容承接路径、学习路线。 + +画法:一条弯曲路径,少量节点,小黑猫牵线、用尾巴钩线或走路。 + +### 小漫画分镜 + +适合:失败到成功、真实过程、吐槽、使用前后变化。 + +画法:2-3 个小场景,每格只表达一个动作。 + +## 原创隐喻生成法 + +每次都从当前文章重新发明隐喻,不能照搬旧图。 + +### 三步 + +1. 把抽象概念换成一个物理动作:卡住、漏掉、变重、分拣、沉淀、发酵、开门、折叠、拆包、回流。 +2. 把系统结构换成一个低科技物件:坏掉的机器、纸箱、抽屉、水管、邮筒、怪表盘、秤、井、梯子、奇怪工位。 +3. 让小黑猫承担动作:不是站旁边,而是卡住、拉错线、守门、搬运、修补、称重、扶梯子、记录、把东西塞进某个怪装置。 + +### 可用物件池 + +- 纸箱、抽屉、漏斗、秤、邮筒、门、井、梯子、水管、线团、闸门、转盘、黑盒、打孔器、晾衣绳。 +- 用时只选 1-2 个,不要堆满。 +- 旧机器、怪工位、实验室、仪表盘只在用户明确要求时使用;默认不要画。 + +### 小黑猫动作池 + +- 拉、扛、塞、捞、压、称、缝、剪、拧、守、推、接、拆、标记、回收。 +- 可以用爪子、尾巴、猫耳的方向辅助表达动作,但不能变成卖萌姿态。 +- 动作要服务核心意思,不要为了怪而怪。 + +## 反复刻规则 + +不要默认打开或复刻 `assets/examples/`。这些图片只用于风格校准,例如线条密度、留白、颜色克制、单个核心动作。使用这些参考时,只把原小黑替换成小黑猫,不要提高场景复杂度。 + +`assets/ip-reference/00-source-safety-audit-cat.png` 是角色真源,只学猫的外形;清单、按钮、机器、文字和构图都不要复刻。`assets/ip-reference/01-approved-simple-funnel-cat.png` 只学画面密度与留白;漏斗、纸堆、箭头位置和文字标注不要复刻。 + +`assets/examples/15-fact-vs-guess-cat.png` 和 `16-content-handoff-door-cat.png` 已通过 90 分角色相似度门槛,用来确认小黑猫换场景后仍稳定;秤、门、卡片和文字同样不能复刻。 + +不要把过往视频里的完整小黑猫页面当默认参考。那些页面常包含多机器、多面板、多角色和大量标注,只能作为“不要默认这么复杂”的反例。 + +除非用户明确说“照这张 / 复刻这个构图 / 用这个案例改”,否则不要直接复用这些旧构图: + +- 传送带两个断点 +- 小黑猫在内容机器里拉判断杆 +- 小黑猫变漏斗分拣流量/信任/转化 +- 小黑猫切素材鱼 +- 小黑猫牵承接路径 +- 小黑猫拉三层信息源 +- 三个小黑猫分别拿喇叭/搭桥/开门 +- 小黑猫盖章话术工具箱 +- 小黑猫举牌看常见坑路径 +- 小黑猫侦探桌面、放大镜、帽子、复杂实验室 +- 三台机器串联的安全审计页面 + +同类主题也要换新隐喻。例如“承接路径”不一定画路线,可以画小黑猫用尾巴把内容尾巴接到门把手;“一鱼多吃”不一定画鱼,可以画小黑猫把一个纸团压成几种形状。 diff --git a/skills/rn-ian-xiaohei-cat-illustrations/references/origin-and-license.md b/skills/rn-ian-xiaohei-cat-illustrations/references/origin-and-license.md new file mode 100644 index 0000000..7f7cbdc --- /dev/null +++ b/skills/rn-ian-xiaohei-cat-illustrations/references/origin-and-license.md @@ -0,0 +1,35 @@ +# 来源、修改与许可 + +## 原始项目 + +- 项目:Ian Xiaohei Illustrations(原版 Xiaohei Skill) +- 作者:Ian(GitHub `helloianneo`) +- 源仓库:https://github.com/helloianneo/ian-xiaohei-illustrations +- 核验版本:`91b560849e8f883922cc2fa8a358a668caa94105` +- 原始许可:MIT License + +本 Skill 保留并改编了原项目的中文文章认知锚点分析、shot list、16:9 白底手绘视觉系统、构图方法和校准样例。当前版本进一步把原版黑色“小黑”角色替换为“小黑猫”IP,增加猫形权威参考图、角色一致性评分、身份保持规则、猫形动作库和更严格的复杂度预算。 + +本改编版不是 Ian 或原始项目发布的官方版本。原项目中的 MIT 许可内容继续按下述许可证使用;本仓库新增和修改部分同时受 rnskill 仓库许可证约束。 + +## MIT License + +Copyright (c) 2026 Ian + +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. diff --git a/skills/rn-ian-xiaohei-cat-illustrations/references/prompt-template.md b/skills/rn-ian-xiaohei-cat-illustrations/references/prompt-template.md new file mode 100644 index 0000000..1578f9c --- /dev/null +++ b/skills/rn-ian-xiaohei-cat-illustrations/references/prompt-template.md @@ -0,0 +1,54 @@ +# 生图提示词模板 + +每张图单独生成。根据正文内容替换变量,不要把多张图拼在一起。 + +```text +Generate one standalone 16:9 horizontal Chinese article illustration. + +Visual DNA: +Pure white background. Minimalist black hand-drawn line art. Slightly wobbly pen lines. Lots of empty white space. Sparse red/orange/blue handwritten Chinese annotations. Clean absurd product-sketch feeling. No gradients, no shadows, no paper texture, no complex background, no commercial vector style, no PPT infographic look, no cute mascot poster, no children's illustration, no realistic UI. + +Input image role: +Use `assets/ip-reference/00-source-safety-audit-cat.png` as the authoritative character identity reference. Match the cat closely, but do not copy its clipboard, control knob, machine, text, or composition. Use `assets/ip-reference/01-approved-simple-funnel-cat.png` only if a second reference is needed for sparse layout and white space, never for identity. + +Recurring IP character required: +小黑猫, the same working cat from the authoritative reference: a large slightly asymmetric solid-black cat head about 1.25-1.5 times the torso width, a smaller narrow black body, one pointed ear taller and more upright while the other is slightly lower and angled outward, two enormous close-set vertical white oval eyes filling about half the face, black oval pupils occupying about one third of each white eye and both shifted in the same looking direction, compact thick arms no longer than the torso, short legs, mitten-like paws, blank serious deadpan expression, and a slightly uneven hand-drawn outline. No mouth, no smile line, no nose, no whiskers, no highlights, no eyelashes. Preserve the recognizable large-head/small-body ratio; do not merge the head and torso into a rounded bean mascot or enlarge the head to twice the torso width. 小黑猫 must perform the core conceptual action, not decorate the scene. Keep the scene simple without weakening character identity. + +Theme: +{正文配图主题} + +Structure type: +{结构类型:Workflow / 系统局部 / 前后对比 / 角色状态 / 概念隐喻 / 方法分层 / 地图路线 / 小漫画分镜} + +Core idea: +{这张图要表达的核心意思} + +Composition: +{具体画面:小黑猫在哪里、正在做什么、主要物件是什么、信息如何流动} + +Suggested elements: +{元素1} / {元素2,最多 1-2 个主要物件} + +Chinese handwritten labels: +{标注词1} / {标注词2} / {标注词3} / {可选标注词4} / {可选标注词5} + +Color use: +Black for main line art and 小黑猫. Orange for main flow/path/arrows. Red only for key warnings/problems/results. Blue only for secondary notes or feedback/system state. + +Constraints: +One image explains only one core structure. Use one 小黑猫 by default; use 2-3 only for before/after or comic panels. Keep the main subject around 35%-55% of the canvas. Preserve at least 45% blank white space. Use at most 3-5 short handwritten Chinese labels. Use only 1-2 main props. Character identity matters more than prop detail. Match the authoritative reference on silhouette, eye geometry, head/body ratio, limbs, expression, and black-fill hand-drawn treatment. Avoid generic black cats, rounded bean mascots, same-width head and torso, perfectly symmetric ears, small or circular eyes, centered pupils, mouth or smile lines, nose, whiskers, highlights, long limbs, four-legged posture, complex machines, multi-screen dashboards, lab scenes, office desk scenes, dense panels, many arrows, many nodes, and full video-page compositions. Do not write a title in the top-left corner. Do not write the structure type on the image. Do not make it a formal diagram, course slide, or dense explainer. Do not copy prior examples or reuse known case compositions unless explicitly requested; invent a fresh visual metaphor for this specific article. It should be clear but not instructional, interesting but not childish, strange but clean. +``` + +## 图像编辑提示 + +去掉左上角标题: + +```text +Edit the provided image. Remove only the handwritten title "{要删除的文字}" and its underline from the top-left corner. Fill that area with the same clean white background, matching the surrounding blank paper. Preserve everything else exactly: characters, labels, paths, line style, composition, aspect ratio, and image quality. Do not add any new text or objects. +``` + +增强怪诞感: + +```text +Regenerate this illustration with the same core meaning and a much simpler layout. Match the character in `assets/ip-reference/00-source-safety-audit-cat.png`: large slightly asymmetric black cat head, smaller narrow body, enormous close-set vertical white oval eyes, same-direction offset black pupils, short thick limbs, no mouth/nose/whiskers, deadpan working-cat posture. Keep 1-2 props, 3-5 short labels, large blank space, and do not copy the reference scene. +``` diff --git a/skills/rn-ian-xiaohei-cat-illustrations/references/qa-checklist.md b/skills/rn-ian-xiaohei-cat-illustrations/references/qa-checklist.md new file mode 100644 index 0000000..e02ddd6 --- /dev/null +++ b/skills/rn-ian-xiaohei-cat-illustrations/references/qa-checklist.md @@ -0,0 +1,68 @@ +# QA Checklist + +## 必过项 + +- 是 16:9 横版。 +- 背景是干净白底。 +- 有小黑猫,且能看出大头小身、略不对称尖耳、巨大白色竖椭圆眼、同向偏移黑瞳和短粗肢体。 +- 已把 `assets/ip-reference/00-source-safety-audit-cat.png` 作为角色参考图传入生成,并且没有复刻它的清单、按钮或机器。 +- 小黑猫相对权威角色参考的加权相似度达到 90 分。 +- 小黑猫承担核心动作,不只是装饰。 +- 没有复刻旧案例构图,而是为当前文章生成了新隐喻。 +- 画面怪诞、有创意、有意思。 +- 简洁清爽,主体占画面约 35%-55%,至少 45% 干净留白。 +- 一张图只讲一个核心结构。 +- 默认只有 1 只小黑猫;前后对比或小漫画最多 2-3 只。 +- 默认只有 1-2 个主要物件。 +- 中文标注少、短、能读,默认 3-5 个。 +- 橙色只用于主路径或箭头。 +- 红色只用于重点、问题、提醒或结果。 +- 蓝色只用于补充说明、反馈或系统状态。 + +## 失败信号 + +出现以下情况,重生成或局部编辑: + +- 左上角有“常见坑 / Workflow / 系统架构图 / 路线图”等标题。 +- 小黑猫像吉祥物、表情包、可爱卡通或真实宠物猫。 +- 小黑猫像普通黑猫,眼睛太小或太圆、瞳孔居中或方向不一致、身体太粗、四足姿态太真实,或出现嘴部表情。 +- 小黑猫缺少猫耳、白圆眼、爪子/尾巴等可识别猫形特征,退回成普通黑色小人。 +- 小黑猫戴帽子、拿放大镜、穿复杂服装、带彩色项圈,变成职业角色或宠物角色。 +- 画面像 PPT、课程课件、正式流程图。 +- 元素太多、箭头太多、节点太多。 +- 出现复杂机器、多屏面板、实验室、办公桌、完整视频页式构图。 +- 文字变成大段解释。 +- 背景有纸纹、阴影、渐变、米色、噪点。 +- 真实 UI 截图或科技感界面。 +- 中文错字严重或标注不可读。 +- 画面太死板,没有荒诞隐喻。 +- 和 `assets/examples/` 里的旧案例构图过于相似。 + +## 迭代方法 + +- 太普通:强化大头小身、巨大椭圆眼、同向偏移瞳孔和死认真气质,再让它成为动作主体。 +- 太复杂:删节点,只保留一只小黑猫、一个动作、1-2 个物件和 3-5 个短标注。 +- 太可爱:强调 deadpan、blank serious expression、not cute、not mascot、not realistic pet cat。 +- 太 PPT:去掉标题、边框、整齐网格和过多箭头,改成手绘场景。 +- 太像旧案例:保留核心意思,换掉主物件和小黑猫动作。 +- 文字错:优先局部编辑;错得多就重生成并减少标注数量。 + +## 角色相似度评分 + +把生成图与 `assets/ip-reference/00-source-safety-audit-cat.png` 并排查看,按 100 分评分: + +- 轮廓 25 分:大而略歪的猫头、头宽约为躯干的 1.25-1.5 倍、一高一直与一低外张的尖耳。 +- 眼睛 25 分:巨大白色竖椭圆、彼此靠近、黑瞳约占三分之一且同向偏移。 +- 头身比例 15 分:头宽明显大于肩宽,头约占角色总高一半。 +- 四肢与姿态 10 分:手臂粗短且不长于躯干、短腿、连指手套式猫爪、认真工作姿态。 +- 面部气质 10 分:无嘴无鼻无胡须,空、呆、冷静,不卖萌。 +- 线条与填色 10 分:纯黑实心、边缘轻微手绘不规则,无毛发、渐变和高光。 +- 场景兼容 5 分:角色自然参与动作,没有被道具改变成职业装扮。 + +总分低于 90 就不交付。轮廓、眼睛、头身比例任一项低于该项满分的 80%,即使总分够也要继续迭代。每轮只修最失真的 1-2 个特征,再重新生成和评分。 + +## 交付判断 + +高质量图应该让读者先觉得“有点怪”,然后 1 秒内看懂结构。 + +如果第一眼像教程页,而不是白纸上的怪诞产品草图,就不合格。 diff --git a/skills/rn-ian-xiaohei-cat-illustrations/references/style-dna.md b/skills/rn-ian-xiaohei-cat-illustrations/references/style-dna.md new file mode 100644 index 0000000..042f761 --- /dev/null +++ b/skills/rn-ian-xiaohei-cat-illustrations/references/style-dna.md @@ -0,0 +1,48 @@ +# 风格 DNA + +## 一句话 + +纯白、极简、手绘、留白、克制、怪诞、产品草图感、中文手写感、结构清楚但不说明书。 + +像一个长期做 AI、产品、设计、开发工具的人,在白纸上随手画出来的一张解释草图。 + +## 必须 + +- 16:9 横版正文配图。 +- 纯白背景:不要米色、暖灰、纸张纹理、渐变、阴影、噪点、复古纸感。 +- 黑色手绘线稿为主:细线、轻微抖动、不机械、不矢量、不厚重描边。 +- 大量留白:主体占画面约 40%-60%,至少 35% 空白,最好有一整块安静区域。 +- 少量中文手写批注:最多 5-8 处,每处尽量 2-8 个字。 +- 一张图只讲一个核心动作、结构、状态或隐喻。 +- 结构要自然表达,不要在图上写结构类型名称。 + +## 颜色 + +- 黑色:主体线稿、角色、框线、结构、主要文字、主体物件。 +- 红色:重点批注、问题、情绪点、关键提醒、结果。 +- 橙色:主流程、路径、箭头、自动化流向、从 A 到 B 的移动关系。 +- 蓝色:补充说明、脑内状态、系统状态、第二层解释、AI/assistant/自动化提示。 + +蓝色不是每张都必须用。颜色要克制,宁可少不要多。 + +## 绝对不要 + +- 不要商业插画。 +- 不要 PPT 信息图。 +- 不要正式流程图。 +- 不要课程课件。 +- 不要可爱卡通海报。 +- 不要儿童插画。 +- 不要复杂架构图。 +- 不要精致扁平插画。 +- 不要科技感 UI。 +- 不要真实 App 截图。 +- 不要复杂背景、渐变、阴影、纹理。 +- 不要把每个节点都解释清楚。 +- 不要左上角写“Workflow 流程图 / 系统架构图 / 常见坑 / 路线图”等类型标题。 + +## 审美方向 + +要怪诞、创意、有意思、简洁清爽、天马行空。 + +不要可爱、幼稚、很复杂、死板。 diff --git a/skills/rn-ian-xiaohei-cat-illustrations/references/xiaohei-cat-ip.md b/skills/rn-ian-xiaohei-cat-illustrations/references/xiaohei-cat-ip.md new file mode 100644 index 0000000..635caa5 --- /dev/null +++ b/skills/rn-ian-xiaohei-cat-illustrations/references/xiaohei-cat-ip.md @@ -0,0 +1,82 @@ +# 小黑猫 IP + +## 角色定义 + +小黑猫是 Ian 中文正文配图的新固定视觉 IP,用来替换旧版黑色小人 IP。 + +默认每张图都要出现小黑猫。小黑猫不是宠物照、吉祥物、贴纸或可爱装饰,而是正在认真参与系统运转的荒诞工作者。 + +关键原则:小黑猫是“原小黑的猫形替换”,不是普通黑猫,也不是更复杂的新卡通主角。默认要保持原小黑的低复杂度,同时保留过往小黑猫素材里更好的 IP 质感。 + +`assets/ip-reference/00-source-safety-audit-cat.png` 是从旧视频原图裁出的权威角色真源。每次生图都必须把它作为第一张参考图传给 `image_gen`,只继承角色外形和黑白手绘质感,不继承安全审计清单、按钮、机器或构图。 + +`assets/ip-reference/01-approved-simple-funnel-cat.png` 只用于校准低复杂度、留白和单动作构图。它的身体过圆、头身过于连成一块,不能覆盖权威角色真源。 + +## 外形 + +- 大头小身:猫头约占角色总高的 45%-55%,头宽约为躯干宽的 1.25-1.5 倍;头与身体可以有一条很窄的白色分界,不能融成圆润黑豆人,也不要把头放大到躯干宽的两倍。 +- 黑色实心猫头略偏圆方、轻微不对称;一只耳朵更高更直,另一只略低并向外张,不能像标准对称 logo。 +- 两只巨大白色竖椭圆眼占脸部约一半面积,彼此靠近;黑色椭圆瞳孔占白眼约 30%-40%,两只瞳孔必须朝同一方向偏移。不要高光、睫毛和彩色虹膜。 +- 无嘴、无笑线、无鼻子、无胡须。空白脸和偏移瞳孔共同形成冷静、困惑又死认真的气质。 +- 身体较窄、短而紧凑;手臂粗而短,长度不超过躯干高度,手掌是连指手套式猫爪;腿也短。黑色肢体可用一两条细白轮廓分开,但不要在身体上画装饰性白色腰线。 +- 身体可以变成黑豆猫、黑盒猫、漏斗猫、影子猫、洞口猫、机器内部黑猫块。 +- 轮廓略微不规则,有手绘感。 +- 整体保持扁平、实心、荒诞,不画真实毛发和复杂纹理。 + +## 复杂度预算 + +默认一张图只用: + +- 1 只小黑猫;前后对比或小漫画最多 2-3 只。 +- 1 个核心动作。 +- 1-2 个主要物件。 +- 3-5 个短中文标注。 +- 至少 45% 干净留白。 + +小黑猫自身不要变成职业角色、宠物角色或普通卡通猫。小工具可以服务动作,但不能让帽子、眼镜、放大镜、背包、彩色配件成为默认形象。 + +## 性格 + +- 很认真,但做的事有点荒诞。 +- 像一个低调的系统操作员。 +- 冷幽默,不卖萌。 +- 有点笨拙,但不蠢。 +- 像在白板草图里真的负责某个工作。 + +## 常见职责 + +让小黑猫承担核心动作: + +- 搬运素材。 +- 用爪子拉线汇聚信息源。 +- 卡在断点里。 +- 在机器里操作“判断”杆。 +- 变成筛选漏斗。 +- 切开“素材鱼”。 +- 盖章承接话术。 +- 牵着承接路径。 +- 举警告牌看坑。 +- 从洞里伸出爪子但接不住内容。 +- 用尾巴钩住路径、标注、线团或警告牌。 +- 搬砖、搭桥、开门、分拣、记录。 + +## 禁止 + +- 不要把小黑猫画成过度可爱的猫咪吉祥物。 +- 不要画成真实宠物猫、儿童卡通猫、表情包猫或日系萌猫。 +- 不要给小黑猫复杂服装、彩色项圈、闪亮眼睛或丰富表情。 +- 不要画成普通四足黑猫、细长黑猫、写实猫轮廓,或带嘴部表情的可爱猫。 +- 不要把眼睛画小或画成正圆;巨大白色竖椭圆眼和同向偏移瞳孔是第一识别点。 +- 不要画嘴、微笑弧线、鼻子、胡须、腮红、眼睛高光或表情符号。 +- 不要把头身画成一个圆润连续的黑豆,也不要画成同头宽的粗壮人形身体。 +- 不要画真实毛发、毛绒质感、渐变阴影或复杂花纹。 +- 不要默认画侦探帽、放大镜、办公桌、电脑屏幕、三台机器、多层仪表盘或实验室场景。 +- 不要让小黑猫只是站在角落里看。 +- 不要让小黑猫抢走结构表达。 +- 不要把小黑猫画得太商业、太圆润、太精致。 + +## 判断标准 + +如果去掉小黑猫,图的核心隐喻还能完全成立,说明小黑猫太装饰了;要重写提示词,让小黑猫成为动作主体。 + +如果看起来只是旧版黑色小人加了耳朵,也不够稳定;要强化大头小身、略歪尖耳、巨大椭圆眼、同向偏移瞳孔和短粗猫爪。生成后必须按 `qa-checklist.md` 的角色相似度评分达到 90 分。 diff --git a/tools/build-skills.sh b/tools/build-skills.sh index fc978c9..991d4d7 100755 --- a/tools/build-skills.sh +++ b/tools/build-skills.sh @@ -11,9 +11,11 @@ group_for() { rn-renhua) echo "01-writing" ;; rn-motion-director) echo "02-video-production" ;; rn-motion-replica) echo "02-video-production" ;; + rn-editorial-collage-motion) echo "02-video-production" ;; rn-dark-saas-video) echo "02-video-production" ;; rn-bw-text-opener) echo "02-video-production" ;; rn-replica-qc) echo "03-quality-control" ;; + rn-ian-xiaohei-cat-illustrations) echo "04-image-generation" ;; *) echo "99-other" ;; esac } @@ -64,6 +66,7 @@ Packed $COUNT skills. Drag individual ZIPs into Trae Solo or extract manually. - 01-writing: 写作精修 - 02-video-production: 视频制作 - 03-quality-control: 视频质检 +- 04-image-generation: 图像生成 EOF (cd "$DIST" && zip -qr "../rnskill-${VERSION}.zip" .)