academic-figure-designer
Unified academic figure designer, semantic color & surface decision engine, and FigureSpec v1 compiler. Handles style selection, reference palette derivation, colorblind-safe token binding, SVMC visual metaphors, and normalized compact prose prompt compilation across classic-tech
Install
npx skills add https://github.com/Azhi-ss/academic-figure-skills/tree/main/academic-figure-designer
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install azhi-ss-academic-figure-skills@llmmart
git clone https://github.com/Azhi-ss/academic-figure-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole azhi-ss/academic-figure-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Academic Figure Designer and Prompt Engine
将科学内容编译成可验收的图示。这里是唯一的设计与 prompt 编译入口;不把提示词修辞当作第二次科学设计。
按请求选择输出
| 用户意图 | 行动与停止点 |
|---|---|
| 构造画图提示词 / 只写 prompt | construct:设计简报与完整 prompt;不生图 |
| 检查或诊断已有 prompt | diagnose:定位问题、影响与最小修正;不擅改文件或生图 |
| 按反馈修改 prompt | revise:改动、保留项及完整新 prompt;不自动生图 |
| 制作图 / 修改图片 | construct 或 revise 后交给 workflow 渲染、目检 |
| 只咨询配色或风格 | Palette Decision;不要求完整拓扑,不生图 |
只问方案时不启动绘图。直接画图时不强加 prompt 确认;按用户的 review 偏好执行。
按需读取
- 构造、诊断或修订决策 →
references/prompt-design-logic.md - 编译 renderer prompt →
references/json-to-prompt.md - 可直接填充的构造/修订样板 →
references/prompt-templates.md - 密度、布局、文字或风格细节 →
references/image-prompt-guide.md - 案例与迁移检验 →
references/prompt-design-cases.md - 实际渲染的结构契约 →
json-schema.md和figure-spec.schema.json - 视觉锚点 →
references/architecture-icons.md,仅使用符合证据的元素 - 色彩与可选风格库 →
references/palettes.md、references/styles/ - 证据不足 →
references/missing-info-policy.md - 图片验收 →
references/render-audit.md
设计流程
- 写出读者问题及图的核心答案,区分主内容、支撑内容、caption-only。
- 从上游分析或用户输入提取稳定 component IDs、typed connections、权限边界、禁止关系及证据。不从参考图借算法,不把缺失证据填成确定事实。
- 在科学骨架明确后、布局定稿前确定风格。复用用户已选风格;有参考图时先查看并提取视觉语法,无参考时选择适合内容的 profile。风格参与后续构图,不作为写完 prompt 后追加的装饰句;详见
references/prompt-design-logic.md。 - 联合科学含义与所选风格设计阅读顺序、主区、语义分组、连线通道及必要视觉锚点。只有真实层级需要时才嵌套;比例是构图辅助。图标、小图、公式卡、机器人或气泡均可选,纯标签节点合法。
- 锁定可见文字、语义颜色与非颜色编码,检查所选风格下的文字容量与可读性;编译前闭合全部边。修订先写 Delta 与 Invariants,颜色修改不改变科学拓扑。
- 将内容、布局与风格统一编译为完整的紧凑自然语言,而非给旧 prompt 叠加风格补丁。prompt-only 在此交付;渲染任务再补齐、校验 FigureSpec 并移交执行。
用户直接描述架构时跳过不必要的仓库扫描。将其记为 sources 中的 user_instruction,证据为原请求;component IDs 使用稳定 snake_case。执行、建议、反馈、存储和异常连接分开,不靠位置推断连线。
风格与语义配色
保留四个 canonical style_profile:
classic-technical:技术线图、精确拓扑、克制色彩、清晰无衬线文字。pastel-airy-ui:轻边界与白色卡片,颜色主要落在 token、曲线和重点,不堆叠卡片。illustrated-modular:有色语义分区、成对浅底/深轮廓、可选择手绘线稿和角色插图;不默认每区同等密度。reference-led:依据已查看的参考图提取布局、线条、填色、字体、插图和留白语法;不等同于手绘风。
色相随职责绑定,不按代码目录数配色。Agentic 图可参考 reasoning 蓝、context 绿、execution 桃、advisory 紫、memory 青、output 金、stop 珊瑚红;这些是领域预设而非通用事实。支持丰富配色、灰度印刷或数据需要的深色背景。遵循参考/用户确定的 surface 和 shadow 规则,避免一处要求 3D 而另一处全局禁止 3D。
正文与底色保持足够对比度;关键差别用颜色加线型、标签或形状双编码。Palette Decision 输出 profile、选择理由、语义绑定、底色/正文/轮廓、一个备选与可复制 tokens。
文字与编译
区域标题通常不超过 5 词、标签/边标签通常不超过 3 词;这是缩写建议,不得破坏科学含义。只放必要且有来源的公式。先移走次要文本,再考虑分图或确定性排版,不通过无限缩小字体增加密度。
模型输入用 compact prose,不用 Markdown 标题、加粗、列表或表格包围指令;保留批准的数学符号及精确标签。默认图题放外部 caption,只有用户或设计明确要求时才显示一个短图题。顺序为目的、构图与组件、闭合边清单、精确可见文字、风格配色、缺陷约束及比例,详见编译器。
渲染交接与验证
实际渲染使用 academic-figure/FigureSpec@1,保持现有 schema 兼容。所有边有正确端点,visible_text 闭合;参考、输出路径与 workspace_root 均来自真实运行环境。prompt-only 不需要编造渲染环境。
渲染前立即执行(脚本路径按实际安装位置解析):
python3 <designer>/scripts/validate_figure_spec.py --strict-v1 --render-ready \
--workspace-root <trusted-actual-root> <spec.json>
prompt_review: requested 展示并停下;confirmed 必须匹配已审核 prompt 的 SHA-256,改变后重新请求审核;waived 内部传参且不在回答中贴出。校验失败不调用 renderer。
交给 academic-figure-workflow 使用当前可用的原生图片工具;每次图片编辑前先看基线图,之后保存新版本并重新逐节点、逐边目检。FigureSpec PASS 不代表图片 PASS。只有 prompt 的产物不宣称已经通过图片验收。
Files (academic-figure-skills)
-
references
-
styles
-
双保真度引导闭环风.md 7.2 KB
# 双保真度引导闭环风 (Dual-Fidelity Loop & Bayesian Optimization) ## 代表论文与配图来源 (Representative Paper & Figure) - **LABO: LLM-Accelerated Bayesian Optimization through Broad Exploration and Selective Experimentation (Chen et al., ICML 2026 / arXiv:2605.22054)**: *Figure 1 (Prior-Guided Initialization & Optimization Loop Workflow)* — 经典的先验大模型推理初始化、双保真度高斯过程代理模型(3D GP Response Surface)、不确定度门禁判定(Gating Criterion $p_\Delta(x^*) < \tau?$)、真机物理实验修正与大模型廉价全局探索的自适应双循环闭环架构。 ## 适用场景 - **双保真度/多保真度优化 (Multi-Fidelity & Active Learning)**:结合昂贵真机实验(如湿实验、耗时物理仿真)与廉价先验模型(如 LLM 推理、低保真代用模型)的自适应优化系统。 - **大模型在环科学发现 (LLM-in-the-loop Scientific Discovery)**:利用 LLM 结构化文献先验进行冷启动探索,并通过残差模型(Discrepancy Modeling)修正认知偏差。 - **自适应门禁决策闭环 (Adaptive Gating & Bayesian Optimization Loop)**:包含明确的不确定度阈值判定分支(如 $p_\Delta < \tau$ 走低成本虚拟循环,反之触发昂贵物理实验)。 - **多维数学与科学图元混合表达**:同时需要 3D 响应曲面、1D 采集函数搜索曲线、认知推理气泡/仪表盘、物理仪器装置与决策流向图。 ## Visual Brief 风格定义 ```json { "style_name": "双保真度引导闭环风", "layer_type": "surface_profile", "style_family": "dual-fidelity-loop", "visual_direction": "two-tier structured macro-container architecture, dual-fidelity paired loop with 3D response surface, gating decision diamond, and scientific instrument grounding", "canvas": { "background": "#FFFFFF", "use_full_canvas": true, "panel_style": "two-tier nested containers with subtle grey dashed borders (#D1D5DB), pure white interior cards with fine 1.5px solid strokes, icon-tagged top section headers" }, "color_palette": { "preset": "Dual-Fidelity Coral & Slate Blue", "primary_high_fidelity": "#DC2626 (Deep Red / Coral #E76F51, fill #FEE2E2)", "secondary_low_fidelity": "#2563EB (Slate Blue / Cobalt #4A90E2, fill #EBF5FF)", "neutral_structure": "#4B5563 (Graphite Slate, fill #F9FAFB, outline #9CA3AF)", "accent_gating_yes": "#16A34A (Emerald Green badge / checkmark)", "accent_gating_no": "#DC2626 (Crimson Red badge / cross)", "rule": "High-fidelity real experiments and discrepancy corrections strictly use warm red/coral; low-fidelity LLM surrogates and global guidance strictly use slate blue; structural axes and containers remain neutral slate." }, "typography": { "font_family": "Academic Sans-Serif & Mathematical Latin Modern (Inter / Arial / Times Roman for formulas)", "section_title": "bold italic 11-13pt with leading icon", "module_header": "bold 10-11pt centered or left-aligned", "body_text": "regular 8-9pt (#24323D)", "formulas": "8-10pt mathematical notation (e.g. f_R(x) = \\rho f_L(x) + \\delta(x))" }, "icon_and_decorations": "3D response surface mesh with dual elevation heatmap, 1D acquisition curve with peak marker, electronic brain with query balloon, uncertainty gauge meter, laboratory glassware and oscilloscope monitor", "constraints": [ "Strict pure white background without heavy dark backdrop", "Two distinct macro stages (Initialization on top ~30% height, Optimization Loop on bottom ~70% height)", "No top title banner across the entire canvas", "Dual circulation arrows connecting gating decision back to surrogate model", "No markdown formatting symbols in prompts" ] } ``` ## Paired semantic tokens | 语义角色 | 建议 token | 视觉特征与代表图元 | |---|---|---| | **High-Fidelity / Real Experiment** | Coral Red (`#FEE2E2` fill, `#DC2626` outline) | 显微镜、烧杯试管、测量波形监视器、残差高亮区 $\mathcal{X}_R^*$ | | **Low-Fidelity / LLM Surrogate** | Slate Blue (`#EBF5FF` fill, `#2563EB` outline) | 芯片/大脑图标、提示词对话框、全局响应曲面平滑底座 | | **Gating / Decision** | Decision Diamond (`#FFFFFF` fill, `#4B5563` outline) | 判定菱形 $p_\Delta(x) < \tau?$、绿色对勾分支、红色叉号分支 | | **Search & Acquisition** | Coordinate Curve (`#F9FAFB` fill, `#4B5563` outline) | 1D 采集函数曲线、极值红点 $x^* = \arg\max \alpha_t(x)$、放大镜 | | **Prior Knowledge / Warm Start** | Neutral Slate (`#F9FAFB` fill, `#9CA3AF` outline) | 文献图例、散点坐标系、参数边界卡片 | ## 内容图示化与 SVMC 科学图元 1. **3D 高斯过程响应曲面 (3D GP Response Surface)**: - 3D 网格地形图,低部呈冷调淡蓝(代表 LLM 全局平滑先验 $f_L(x)$),顶部高残差区域呈暖红/珊瑚色并以红色虚线椭圆圈出(代表聚焦修正区 $\mathcal{X}_R^*$); - 配套给出残差数学耦合公式卡片:$f_R(x) = \rho f_L(x) + \delta(x)$ 与协方差假设。 2. **1D 采集函数极值搜索曲线 (1D Acquisition Curve)**: - $X-Y$ 坐标轴展示多峰采集函数曲线 $\alpha_t(x)$,黑灰实线搭配散点采样历史,曲线最高点处标注醒目红色实心圆点及放大镜图标,指向 $x^* = \arg\max \alpha_t(x)$。 3. **大模型认知推理与不确定度卡片 (Cognitive Reasoning Card)**: - 包含芯片与大脑结合的简笔线稿,带有带引号的自然语言 Prompt 气泡(例如 *"Predict property for candidate x with prior..."*); - 附带半圆形不确定度度量表(Uncertainty Gauge Meter)与结构化预测数据表格。 4. **真实物理/化学实验卡片 (Real-Fidelity Experiments Card)**: - 包含实验仪器(烧瓶、显微镜、试管)与测量仪器(电脑监视器显示条形图/折线图),代表高保真真机测试。 5. **宽幅循环反馈导引 (Thick Circulation Ribbon Arrows)**: - 红色弧形实线箭头从 Real-fidelity 实验返回更新代理模型;蓝色弧形箭头从 LLM-fidelity 预测返回更新代理模型;灰色渐变主干箭头按顺时针流向串联各个决策阶段。 ## 可复用 prompt 片段 ```text Two-tier structured academic workflow diagram with dual-fidelity paired color system on pure white canvas (#FFFFFF), aspect ratio 16:9. Top container represents Prior-Guided Initialization with three horizontal cards (Prior Knowledge, LLM Reasoning, Warm Starts). Bottom container represents Optimization Loop featuring 3D Gaussian Process response surface mesh, 1D acquisition curve with maximum point marker, LLM-fidelity estimation with prompt bubbles and uncertainty gauge meter, Gating Criterion decision diamond branching into red Real-Fidelity Loop and blue LLM-Fidelity Loop, and laboratory experiment instruments. Connected by thick curved circulation arrows. Crisp clean lines, publication-grade serif math typography and sans-serif labels. No top title banner across canvas. ``` ## 完成检查 - [x] 明确对标 LABO (arXiv:2605.22054) Fig 1 原图视觉语法; - [x] 包含双层容器架构与双保真度配对色彩规则; - [x] 定义了 3D 响应曲面、1D 采集函数、不确定度仪表盘等 SVMC 科学图元; - [x] 提示词格式严谨,无 Markdown 字符泄漏与顶置大标题。 -
对比消融实验风.md 3.3 KB
# 对比消融实验风 (Purple-Green Contrast & Ablation) ## 代表论文与配图来源 (Representative Paper & Figure) - **KAN: Kolmogorov-Arnold Networks (Liu et al., MIT/Caltech, arXiv:2404.19756)**: *Figure 0.1 & Figure 2.2 (MLP vs KAN comparison)* — 经典的节点固定激活函数与线性权重边 vs 节点纯求和与边上可学习 1D B-样条非线性曲线的高对比架构消融。 - **SimPO: Simple Preference Optimization (Meng et al., Princeton, arXiv:2405.14734)**: *Figure 1 (DPO vs SimPO training & memory footprint)* — 双模型常驻高显存瓶颈 vs 单模型参考无关直接对齐优化的训练消融对比。 - **LoRA: Low-Rank Adaptation (Hu et al., ICLR 2022)**: *Figure 1 (LoRA reparametrization compared with Full Fine-Tuning)* — 左右对齐的冻结预训练权重 vs 注入低秩矩阵 $A \times B$ 的参数高效分支对比。 - **ControlNet (Zhang et al., ICCV 2023)**: *Figure 2 (ControlNet architecture)* — 经典的 Locked Copy 与 Trainable Copy 双分支平行对比。 **适用场景:** - Baseline vs. Proposed 方法对比图 - 消融实验 (Ablation Study) 架构分支对比 - Dual-Branch 双流网络 (如 Teacher-Student, Generator-Discriminator) 有参考图时优先匹配其比较尺度、panel 表面和强调方式;不复制标签、品牌资产或结果。颜色必须由显式 legend/标签解释,不默认“绿色就是 ours”。 **Visual Brief 风格定义:** ```json { "style_name": "对比消融实验风", "layer_type": "composition_variant", "style_family": "inherit", "visual_direction": "high-contrast multi-branch comparison diagram, clearly distinguishing baseline vs proposed innovation with sharp categorical separation", "canvas": { "background": "#FFFFFF", "use_full_canvas": true, "panel_style": "split dual-column or parallel flow layout, distinct colored borders for contrasting branches" }, "color_palette": { "preset": "Purple-Green or Teal-Coral Categorical", "primary": "#7570B3 (Deep Purple - Category A)", "secondary": "#1B9E77 (Deep Emerald Green - Category B)", "accent": "#D95F02 (Orange - Verified shared or fusion element only)", "neutral": "#F5F5F5 (Subtle container tint), #333333 (Text)", "rule": "use distinct, labeled category colors for parallel columns; identify the proposed method with text, shape, or border in addition to hue", "semantic_binding": { "branch_a": "#7570B3 (Purple; bind to baseline/ours only from FigureSpec)", "branch_b": "#1B9E77 (Emerald Green; bind to baseline/ours only from FigureSpec)", "verified_shared_or_fusion": "#D95F02 (Orange Bridge)", "shared_backbone": "#666666 (Gray)" } }, "typography": { "font_family": "Clean Technical Sans (Inter / Roboto / Arial)", "title": "bold 10-12pt", "column_headers": "bold 10pt with branch color indicator (e.g. (a) Traditional vs (b) Ours)", "labels": "regular 8-9pt" }, "icon_and_decorations": "side-by-side comparative boxes and highlighted difference markers; show a numeric delta only when FigureSpec supplies a verified metric and exact value", "constraints": [ "Use a consistent white, near-white, or reference-matched background across compared panels", "Strict alignment between comparative panels (same vertical/horizontal scale)", "High visual symmetry for fair side-by-side comparison" ] } ``` -
有色语义分区图示风.md 5.2 KB
# 有色语义分区图示风 (Tinted Semantic Zones) ## 兼容性与职责 本文件保留原有风格名,作为**颜色与材质层**使用:它规定语义区域如何使用柔彩 fill、深色 outline、标题色和 icon accent,但不强制三栏结构、特定算法图、实验器材或机器人形象。 需要非对称 hero 构图、手绘式标题和叙事插画时,组合使用 [编辑手绘模块风.md](编辑手绘模块风.md)。仅需要柔彩分区时,本文件可以独立配合 pipeline、radial loop、comparison 或其他内容驱动布局。 ## 代表论文与配图来源 (Representative Paper & Figure) - **DASH (arXiv:2608.00641)**: *Figure 1 (Overview of the DASH framework)* — 柔彩填充 (#F0FDF4 Mint, #F5F3FF Lavender, #FFF7ED Peach)、同色深描边与语义区域划分。 - **Agentic-MatriBO**: *Figure 1 (System Architecture)* — 3-Critic 评价门禁与 ALBL 双引擎语义分区。 ## 适用场景 - 多个子系统需要快速区分,但单色层级不足以传达角色 - 科学工作流、agentic system、数据与执行边界、记忆/恢复或多阶段决策 - 参考图使用低饱和大色区和同色系深描边 - 用户希望柔彩但不想要白卡片/阴影的 airy UI 效果 不按模块数量自动启用本风格。若结构属于一个连续层级或用户明确要求单色,可改用蓝调或灰度 profile。 ## 参考图优先 有参考图时,先记录其: - 色区数量与相对面积 - fill/outline/title/icon 的配对关系 - 描边强度、圆角和阴影 - 色彩承载的是语义、状态还是顺序 - 子卡片是否存在以及嵌套深度 参考图语法优先于下列默认 token。只复用视觉原则;不得复制其文字、logo、品牌插画、系统拓扑、数据或性能结论。 ## Paired semantic tokens 唯一颜色事实源是相邻 [`palettes.md`](../palettes.md) 参考中的 **I1 Illustrated Zones**。每个 token 包含: ```yaml layer_type: color_material_layer style_family: inherit semantic_zone: soft_fill: "#......" dark_outline: "#......" title_text: "#......" icon_accent: "#......" ``` 默认语义映射如下;它是可调整的论文内约定,不是通用 ontology。 | 语义角色 | 建议 token | 辅助编码 | |---|---|---| | reasoning / planning / agent policy | I1 Blue | 循环、思考或规划图标 | | evidence / context / scoped input | I1 Green | 文档、数据或 scope 形状 | | deterministic execution / harness / core operation | I1 Peach | 实线流程和执行器图标 | | advisory / council / uncertainty / alternative | I1 Purple | 虚线、optional pill 或分支形状 | | memory / provenance / recovery | I1 Cyan | 存储、时间链或 checkpoint 图标 | | output / report / accepted result | I1 Gold | 明确 terminal/output 形状 | | exception / stop / failure | I1 Coral | 不同线型与显式标签;稀疏使用 | 只激活图中真实存在的 token。重复角色复用颜色;相邻区域还需通过标题、位置、形状或线型区分,不能只依赖 hue。 ## 材质规则 - 画布通常为白色或投稿模板允许的近白色 - 主语义区使用 I1 `soft_fill`,不是高饱和实心色块 - 外框使用同一 token 的 `dark_outline`,建议 1.5–2.5px,按导出尺寸调整 - 标题使用 `title_text`;普通小字统一使用高对比中性色 `#24323D` - 图标以深描边为主,可加入一个 `icon_accent` - illustrated modular 组合下不使用 drop shadow;若参考明确为 airy UI,则应改用“现代柔彩空气风”而不是偷偷加入阴影 - 子卡片可用白色或更浅的同色 fill;嵌套深度由构图 profile 决定,通常不超过一层 ## 内容图示化 图形锚点应来自真实内容。例如: - 数据或证据 → 文档、表格、散点、分布或数据载体 - 规划或策略 → 路径、候选、决策分支或短 checklist - 执行 → 代码、仪器、计算过程或确定性操作符 - 记忆与恢复 → 数据库、事件链、checkpoint 或版本状态 - 输出 → 报告、候选结果或明确终点 不要为追求“科学感”自动添加 GP 曲线、试管、分子、机器人或任何不在系统中的对象。图标是识别辅助,不是每个框的强制配额。 ## 可复用 prompt 片段 ```text Use tinted semantic zones with paired tokens from the approved palette. For each zone, specify a low-saturation soft fill, a darker same-hue outline, a validated title color, and one controlled icon accent. Bind colors to semantic roles and reuse them consistently; do not assign colors by left-to-right order. Keep small body text neutral and high-contrast. Preserve the supplied reference's observable surface grammar without copying its labels, branded assets, topology, or content. ``` ## 完成检查 - [ ] paired tokens 来自相邻 `palettes.md` 参考或经验证的 reference-derived pairs - [ ] 没有 module-count → monochrome/polychrome 的硬切换 - [ ] 色区表达真实语义,重复角色保持同色 - [ ] 小字与实际背景达到可读对比度 - [ ] 关键类别同时使用标签、形状、位置或线型编码 - [ ] 未强制插入与内容无关的图表、实验器材或角色插画 - [ ] 未复制参考图的文字、品牌、拓扑或结果 -
现代前沿技术框线风.md 3.4 KB
# 现代前沿技术框线风 (Modern Technical Vector / legacy alias: 经典学术框线风) ## 代表论文与配图来源 (Representative Paper & Figure) - **DeepSeek-V3 (arXiv:2412.19437, 2024)**: *Figure 2 (DeepSeek-V3 architecture overview)* — 经典的 Multi-Head Latent Attention (MLA) 低秩 KV 压缩、解耦 RoPE 位置编码与 DeepSeekMoE 动态门控路由架构。 - **DiT: Scalable Diffusion Models with Transformers (Peebles & Xie, ICCV 2023)**: *Figure 2 (DiT block overview)* — Patchify 图像块化、AdaLN-Zero 仿射缩放与残差连接。 - **Mamba: Linear-Time Sequence Modeling with Selective State Spaces (Gu & Dao, ICML 2024)**: *Figure 1 (Selective SSM architecture)* — 高对比硬件感知 GPU SRAM/HBM 内存层级与离散状态转移矩阵流。 **典型场景:** - 深度学习前沿模型(LLM、Diffusion、MoE、SSM、Transformer)的核心张量架构图 - 包含精确张量维度标注 ($B \times T \times D$、低秩压缩 $d_c=512$、注意力头数 $n_{heads}=128$) - 需要公式级运算核心(如 $\frac{Q \cdot K^T}{\sqrt{d}}$、Top-K 门控柱状图、残差求和 $\oplus$)的严肃顶会正文配图 - 需要严格纯白底、高印刷质量和无多余装饰的矢量架构图 venue 名称和模块数量不自动触发本风格。有参考图时,先匹配其表面、描边、圆角和布局;只复用视觉语法,不复制内容或品牌资产。 **Visual Brief 风格定义:** ```json { "style_name": "经典学术框线风", "layer_type": "surface_profile", "style_family": "classic-technical", "visual_direction": "formal compact technical architecture diagram, disciplined geometry, restrained flat surfaces, and high legibility", "canvas": { "background": "#FFFFFF or reference-matched near-white", "use_full_canvas": true, "panel_style": "flat rectangular boxes with restrained corner radius and fine stroke hierarchy; white, near-white, or very pale grouping tint according to content/reference" }, "color_palette": { "preset": "Okabe-Ito or ML TopConf Colorblind", "rule": "use color sparingly for stable categories and status; pale grouping fills are allowed; activate only the semantic colors the figure needs", "semantic_binding": { "input_data": "#4285F4 (Soft Blue)", "backbone_core": "#6A5ACD (Soft Indigo)", "loss_supervision": "#D95F02 (Soft Coral/Vermilion)", "output_prediction": "#1B9E77 (Soft Mint/Green)", "frozen_pretrained": "#7570B3 (Neutral Slate Gray, dashed border)" } }, "typography": { "font_family": "Technical Sans-Serif (Arial / Helvetica / Inter / Roboto)", "title": "bold 10-12pt, left/center aligned", "labels": "regular 8-9pt", "tensor_shapes": "6-7pt monospace / italic (e.g., [B, C, H, W])" }, "icon_and_decorations": "clean geometric 2D symbols selected only from FigureSpec; neural-network operators such as Conv, Attention, Concat, or Add are allowed only when the evidence declares them", "constraints": [ "Prefer white or near-white canvas unless the user/reference specifies another legible surface", "Keep technical modules restrained; allow pale group fills when they clarify hierarchy", "Avoid unintended drop shadows, gradient washes, and 3D isometric decoration", "Represent frozen vs trainable status only when FigureSpec declares that distinction", "Use disciplined alignment and the connector grammar required by the topology/reference" ] } ``` -
现代柔彩空气风.md 8 KB
# 现代柔彩空气风 (Pastel Airy UI / Modern Pastel Airy) ## 职责边界 本 profile 表达**纯白高留白底色、柔彩浮动卡片、虚线作用域容器、深灰实体锚点与极简正交走线**的现代学术空气感 (Airy UI) 语法。它特别适用于智能体交互决策、人机接口、代理模型优化闭环与轻量 Token 流系统;区别于大面积同色深描边与手绘叙事的 [编辑手绘模块风.md](编辑手绘模块风.md)。 ## 代表论文与配图来源 (Representative Paper & Figure) - **Agentic Bayesian Optimization through Surrogate-Augmented Autoresearch (Brunzema et al., Meta & RWTH Aachen, arXiv:2608.00316, 2026)**: *Figure 1 (Standard vs. Agentic Bayesian Optimization)* & *Figure 3 (Sara & Lenz Loop)* — 经典的柔杏橙粉高斯过程代理模型卡片、柔雾冰蓝智能体决策中枢、石墨深灰真实黑盒评估高对比锚点、叠层浅灰上下文演进卡片、虚线作用域框与极简正交反馈流。 - **SWE-agent (Yang et al., ICML 2024)**: *Figure 2 (SWE-agent ACI Overview)* — 纯白浮动卡片、CLI 终端仿真交互视窗、文件树结构、Diff 补丁与优雅柔彩状态 Pill。 - **Voyager (Wang et al., NeurIPS 2023)**: *Figure 1 (An Open-Ended Embodied Agent with LLMs)* — 纯白卡片式 Agent-Environment 交互流、Skill 迭代库与高留白空气感布局。 - **ReAct (Yao et al., ICLR 2023)**: *Figure 1 / Figure 2 (Synergizing Reasoning and Acting)* — 纯白浮动卡片、Reasoning/Act/Obs 的轻量悬浮 Token 流与现代 UI 交互感。 - **Reflexion (Shinn et al., NeurIPS 2023)**: *Figure 1 (Reflexion Architecture)* — 白色浮动卡片、Actor/Evaluator/Self-Reflection 循环与轻量状态 Pill。 ## 适用场景 - **智能体闭环优化与人机交互 (Agentic Optimization & Interactive Loops)**:LLM 决策体与确定性/统计学底层工具的双向协同。 - **系统对比与消融架构 (System Comparison & Modular Flow)**:如传统固定策略 vs 智能体自适应闭环的左右分栏对照。 - **Token flow、概念 pill、界面式信息关系**:需要清晰、优雅、呼吸感强的现代顶会配图。 - 用户或参考图明确使用柔彩圆角白卡片与高对比实体操作块。 ## Visual Brief 风格定义 ```json { "style_name": "现代柔彩空气风", "layer_type": "surface_profile", "style_family": "pastel-airy-ui", "visual_direction": "airy academic token-flow and agentic loop diagram with pure white canvas, soft pastel floating cards, dashed scope enclosures, deep charcoal execution anchors, and minimal orthogonal wiring", "canvas": { "background": "#FFFFFF (Pure clean white)", "use_full_canvas": true, "panel_style": "floating rounded cards with 10-14px corner radius, faint neutral border (#E2E8F0) or subtle elevation, dashed group boundaries (#94A3B8), stacked evolution cards with layered shadows", "spacing": "generous whitespace and airy breathing room; never clutter panels merely to satisfy density" }, "color_palette": { "preset": "Airy Pastel & Slate Anchor (P2/Agentic-BO)", "tokens": { "soft_peach_surrogate": "#FAE8DC / #FCEFE6 (Soft warm apricot/peach fill, dark text #1E293B)", "soft_periwinkle_agent": "#DBE7FB / #E0EDFD (Soft pastel baby blue fill, dark navy text #0F172A)", "charcoal_anchor_eval": "#4B5563 / #505050 (Deep slate charcoal fill, crisp white text #FFFFFF)", "neutral_gray_buffer": "#E9E9EC / #F3F4F6 (Soft neutral light gray fill, dark slate text #334155)" }, "rule": "Statistical/surrogate modules strictly use soft apricot/peach; intelligent LLM agents strictly use soft periwinkle blue; expensive ground-truth black-box evaluation strictly uses high-contrast deep charcoal with white text; accumulated data and context use neutral light gray." }, "typography": { "font_family": "Academic Sans-Serif (Inter / Latin Modern Sans) combined with LaTeX Mathematical Serif (Computer Modern)", "math_notation": "Italic serif symbols (e.g., x_{t+1}, \\tilde{x}, \\mathcal{K}_t, \\mathcal{D}_t, \\Pi_0, c_t, h(\\cdot))", "labels": "Clean, compact sans-serif 8-10pt" }, "icon_and_decorations": "Stacked context cards with dashed offsets, dashed fixed-policy container, sleek orthogonal connectors with directional micro-labels (proposal, reconfigure, metrics, observe)", "constraints": [ "Strict pure white canvas (#FFFFFF) without heavy colored backdrop", "No top title banner spanning across canvas", "No heavy drop shadows, glossy 3D chrome, or thick comic cartoon strokes", "No markdown formatting symbols in prompts" ] } ``` ## Paired semantic tokens | 语义角色 | 建议 token | 视觉特征与代表图元 | |---|---|---| | **Surrogate Backend / Math Optimization** | Soft Apricot (`#FAE8DC` / `#FCEFE6`) | 柔杏橙粉圆角卡片,`GP surrogate + acquisition \alpha`,`\arg\max \alpha` | | **Agent / Central Decision Maker** | Periwinkle Blue (`#DBE7FB` / `#E0EDFD`) | 柔雾冰蓝圆角卡片,`agent \mathbb{A} selects x_{t+1}`,思维决策痕迹 | | **Expensive Ground-Truth Evaluation** | Deep Slate Charcoal (`#4B5563` / `#505050`) | 高对比实体暗色胶囊卡片,`evaluate h(\cdot)`,纯白高亮文字 | | **Data Memory / Context Buffer** | Soft Neutral Gray (`#E9E9EC` / `#F3F4F6`) | 浅灰圆角卡片,`append to \mathcal{D}_t`,多层叠放动态 `context \mathcal{K}_t` | | **Scope Enclosure / Policy Boundary** | Dashed Gray Outline (`#94A3B8`, dashed `4,4`) | 虚线圆角边界框,`fixed policy \Pi_0`,标注策略封闭域 | ## 内容图示化与 SVMC 科学图元 1. **叠层演进上下文卡片 (Stacked Evolution Context Cards)**: - 多层轻微偏移叠放的浅灰色卡片,边缘带有精细虚线,代表随时间动态累积与修订的自然语言上下文 $\mathcal{K}_t$(*added / revised over time*)。 2. **策略作用域虚线容器 (Dashed Scope Container)**: - 包裹代理模型与决策选择步骤的灰色细虚线框,上方标注固定策略符号 $\Pi_0$,清晰表达传统优化策略的静态不可变性。 3. **高对比实体评估锚点 (Charcoal Evaluation Anchor)**: - 采用深石墨灰实底与纯白文字,视觉上形成强烈的“昂贵黑盒物理/系统执行”锚点感,与上层浅色数学与智能体模块形成鲜明层级对比。 4. **双向正交协同走线 (Bi-directional Orthogonal Coordination Channels)**: - 纤细正交双向箭头(`proposal \tilde{x}, diagnostics \downarrow` 与 `reconfigure c_t \uparrow`),精准表达 Agent 对底层后端的查询与重构交互。 ## 可复用 prompt 片段 ```text Modern pastel airy academic architecture diagram on pure white canvas (#FFFFFF), aspect ratio 16:9. Two side-by-side comparative panels illustrating Standard Bayesian Optimization versus Agentic Bayesian Optimization (arXiv:2608.00316 Figure 1). Left panel represents Standard BO featuring a dashed fixed-policy container enclosing a soft apricot GP surrogate card and argmax acquisition card, leading down to a deep charcoal solid evaluate block and light gray dataset buffer with feedback loop. Right panel represents Agentic BO featuring a central soft pastel periwinkle blue LLM Agent card interacting bidirectionally with a top soft apricot surrogate backend, receiving layered stacked dashed Context cards, dispatching queries to a deep charcoal solid evaluate block, and updating a light gray dataset buffer with observation and reconfiguration feedback loops. Clean orthogonal connectors with crisp mathematical annotations, LaTeX serif variable formatting, generous whitespace, airy breathing room. No top title banner across canvas. ``` ## 完成检查 - [x] 明确对标 Brunzema et al. (arXiv:2608.00316) Fig 1 与 Fig 3 原图视觉语法; - [x] 定义了柔杏橙粉、柔雾冰蓝、深灰实体锚点与浅灰叠层上下文等 Paired Pastel Tokens; - [x] 包含虚线作用域容器、叠层演进卡片与双向正交协同走线等 SVMC 科学图元; - [x] 提示词格式严谨,零 Markdown 字符泄漏,严格抑制顶置大标题。 -
编辑手绘模块风.md 10.7 KB
# 编辑手绘模块风 (Illustrated Modular / Editorial Hand-drawn) ## 兼容性与职责 本文件保留原有风格名,定义一个完整的 **illustrated modular** 构图 profile:非对称 hero、柔彩语义区、共用深墨或同色深描边、手绘式短标题、受控线稿插画和拓扑校验。 ## 代表论文与配图来源 (Representative Paper & Figure) - **MLEvolve (arXiv:2606.06473)**: *Figure 1–2* — 只作为可观察视觉语法参考:柔彩模块分区、圆润深色描边、手写感标题、线稿图标与叙事式流向。不复制该论文的文字、拓扑或结果。 - **Agentic-MatriBO**: *Figure 1 (System Architecture)* — 左侧 `Agentic Reasoning` 主区,右上 `Deterministic BO Harness` 与右下 `Memory, Provenance & Recovery` 堆叠支撑区;以实线表示确定性执行,紫色虚线表示建议/反馈,珊瑚色表示 STOP 直接例外,并显式标注权限与持久化边界。 ## 参考图使用边界 本 profile 可以从公开或用户提供的图中归纳可观察的构图、表面、描边、字体气质、图标复杂度和连线语法,但不应声称获得原作者 prompt、源文件、模型或生成流程。不得复制参考图的文字、logo、品牌插画、系统拓扑、实验数据或性能结论。 ## 适用场景 用于用户明确要求以下效果时: - “agent 画的论文图”“手绘论文框架图”“像编辑插画一样的架构图”; - 多智能体、长程工作流、科学优化闭环、记忆系统或复杂方法总览; - 需要比企业泳道图更有叙事性,但仍须保持论文级可读性。 不用于严格黑白印刷、精确电路拓扑、纯数学证明图或必须逐像素复刻的 技术矢量图。 ## 核心视觉语法 ### 1. 画布与面板 - 通常使用白色或近白画布;遵循投稿要求和参考图,不使用无意的渐变、玻璃拟态或暗色装饰背景。 - 使用内容驱动的非对称语义区,而不是等宽泳道或等大卡片矩阵。 - 大区采用低饱和近白填色。区域描边可使用经验证的共用深墨色,或参考图明确采用的同色系深描边;标题仍可与区域语义色匹配。 - 圆角和线宽按导出尺寸调整;外框通常 1.5–2.5px,不使用投影。 - 允许一层内部子卡,禁止多层 box-in-box 嵌套。 - 留白由标签长度、箭头通道和视觉层级决定,优先保证主叙事路径和反馈回路清楚。 - 默认将论文题名留在外部 caption;若用户或参考图明确要求,可在画布上保留一个短小、非横幅式的总标题,并为它预留足够留白。 ### 2. 构图模式 根据内容选择一种,不机械照搬参考图。 **Overview narrative** - 以问题、输入或约束建立起点; - 让一个可识别的循环、决策或核心机制成为视觉中心; - 支撑模块与输出围绕真实关系布置,不固定左/中/右模板; - 避免所有模块同等突出。 **Detailed modular framework** - 通常把约 35–55% 画面给核心 hero panel,并按内容调整; - 其余区域由大小不同的支撑 panel 按语义关系拼接; - 主流程使用统一深墨色实线箭头; - 反馈、参考、可选和异常路径用不同颜色或虚实线重复编码; - 图例只解释真正存在的线型,不用图例掩盖含义冲突。 **Left hero + stacked support(可选变体)** - 将约 35–45% 宽度交给左侧推理、决策或反馈 hero,右侧约 55–65% 堆叠两个上下支撑区; - 使用可见边界或稳定沟槽区分“建议性推理”与“权威性执行”; - 右上优先承载已执行的主流水线,右下承载并行记忆、溯源或恢复模块; - 仅当科学语义符合这种主从关系时使用,不将它当作 illustrated-modular 的唯一布局。 ### 3. 字体 当用户明确要求手绘式学术信息图时: - 主标题:选择圆润、受控的 hand-lettered display face;可用 Comic Neue、Kalam 或参考图中可合法使用的相近字体; - 模块标题:同一 display family 的 semibold/bold 变体; - 正文:默认使用 Inter、Arial、Nunito 或其他高可读 sans-serif;当用户/参考图明确采用整套手写字体时,可使用同 family 的受控 regular 正文,但必须在最终宽度下校验可读性; - 手写注释:仅在短注释中少量使用,并遵循参考图; - 数学:使用排版稳定的数学字体,不强迫手写化。 默认将手写感集中在标题、短标签和少量注释。只有在用户/参考图明确支持时才延伸到短正文,且不得因模仿手写而降低缩放后的可读性。 ### 4. 图标与插画 - 使用圆润、友好的共用深墨色线稿,最多加入一个所属语义区的强调色。 - 可组合文档、数据库、图表、放大镜、节点图、齿轮、文件夹等通用 学术图标。 - 机器人、人物、对话气泡仅在它们表达真实系统角色时使用。 - 不复制参考图的机器人、logo、benchmark、搜索树或品牌化插画。 - 禁止 emoji glyph、写实照片、3D chrome 和装饰性电路纹理。 ## 色彩与材质 使用相邻 [`palettes.md`](../palettes.md) 参考中的 **I1 Illustrated Zones** 作为无参考图时的默认 paired token 集。不要在本文件复制另一套近似 Hex,以免 fill、outline、title 和 icon accent 漂移。 推荐语义绑定: | 角色 | I1 token | |---|---| | 推理 / 规划 / agent policy | I1 Blue | | 证据 / 上下文 / scoped input | I1 Green | | 确定性执行 / harness / core operation | I1 Peach | | 建议 / council / uncertainty / alternative | I1 Purple | | 记忆 / provenance / recovery | I1 Cyan | | 输出 / report / accepted result | I1 Gold | | 异常 / stop / failure | I1 Coral | 普通小字和全局结构线使用 `#24323D` 或经实际背景验证的深中性/深墨色。区域色主要承载填色、标题和少量图标强调,不得让跨区主流箭头随意换色。颜色必须绑定真实语义,不按从左到右顺序机械分配;异常色只用于真正的终止、失败或直接例外路径,并同时使用标签/形状/线型编码。 Agentic-MatriBO 展示图采用一组 **reference-derived** 映射,它不改写 I1 的全局默认:推理区使用 I1 Blue,确定性 harness 使用 I1 Peach,记忆/溯源/恢复区使用 I1 Green,council、advisory 和 feedback 使用 I1 Purple 虚线,report 可使用 I1 Gold,STOP/直接例外使用 I1 Coral 并同时显示文本或形状。共用结构墨色可从经验证的高对比深中性色中取值;该展示图使用深墨蓝 `#042433`,但它不是全局 palette SSOT 的新默认。 ## Reference-aware Prompt 模板 以下模板根据可观察视觉语法生成,**不是任何参考图的原始 prompt**。 用已验证的组件、连接和可见文字替换花括号变量。 ```text Create a publication-ready {aspect_ratio} hand-drawn editorial scientific infographic illustrating the {system_or_method_topic}. Preserve the supplied reference grammar when available. Use a white or near-white canvas and content-driven asymmetric rounded semantic regions. Give each region its approved I1/reference-derived soft fill, validated common structural ink or darker same-hue outline, title color, and controlled icon accent. Use a rounded hand-lettered display face for module headings. Use highly legible sans-serif for small body text by default; when the user or reference explicitly uses a coherent handwritten type system, use its controlled regular face for short body labels and verify readability at final size. By default omit the paper title because it belongs in the external caption. If the user or supplied reference explicitly requires it, render exactly one short hand-lettered overall title with ample whitespace, never a full-width banner. Make “{hero_mechanism}” the visual focal point. Compose the other regions around it according to their real relationships, not as equal corporate swimlanes. Use at most one level of white or lighter subcards. Keep visible text short and exactly matched to the approved label list. Reserve enough negative space for clean arrow routes and downscaled readability. Semantic region {region_name}: {exact components, internal order, icons, and short labels} Required connections: {one explicit source -> destination edge per line, including direction, line style, color role, and exact edge label} Forbidden connections: {one prohibited source -> destination edge per line} Use solid dark arrows only for executed forward flow. Use colored dashed arrows for advisory, reference, optional, or feedback flow, and state the meaning beside the edge. Encode exceptions with both a distinct color and an explicit label. Do not invent modules or join independent stores into a serial pipeline. Palette: use the approved paired tokens from the adjacent palettes reference. State each active semantic zone as soft_fill / dark_outline / title_text / icon_accent; use neutral #24323D for small body text. No unintended or duplicated title banner, no copied branding, no copied topology, no photorealism, no gradients, no shadows, no 3D rendering, no emoji glyphs, no dark background, no equal-card dashboard, no extra text, and no performance claims. ``` ## 拓扑可靠性约束 生成 prompt 前,必须从 FigureSpec 中分别列出: - `required_connections[]`:每条边的 source、destination、direction、 kind 和可见标签; - `forbidden_connections[]`:容易被模型误连的边; - `parallel_groups[]`:并列存储或并行候选不得被串成流水线; - `authority_boundaries[]`:跨边界的允许边和禁止边。 首次渲染后按原尺寸检查每条边的两个端点。使用 Codex 做局部图像编辑时, 同时提供参考图(若有),明确锁定已经正确的 hero 构图、paired tokens、 标题风格和区域边界;只描述“删除/增加哪条边、保留哪些正确区域”,不要 重新要求整图换风格。若局部语义编辑仍无法稳定修正,改用 SVG / Draw.io / Typst 或混合文字覆盖层,不继续依赖随机重绘。 ## 完成检查 - [ ] 参考图只用于视觉语法,没有声称获得原始 prompt 或源文件; - [ ] 有一个清晰 hero mechanism; - [ ] 语义区不是等宽企业泳道; - [ ] 大色块低饱和、使用经验证的共用深墨或同色深描边、无阴影; - [ ] 总标题选择与用户/参考图的明确要求一致,且没有意外的横幅或重复标题; - [ ] 标题有手绘感,正文缩放后仍可读; - [ ] 图标表达真实概念而非装饰; - [ ] required / forbidden connections 均已进入 prompt; - [ ] 并行模块没有被误画成串行; - [ ] paired tokens 来自相邻 `palettes.md` 参考或经过对比度验证的 reference-derived pairs; - [ ] 未复制参考论文的文字、logo、品牌插画、系统拓扑或结果。
-
-
architecture-icons.md 10.6 KB
# Architecture Icons and Visual Vocabulary Use visual anchors when they clarify a scientific role or establish the figure's visual story. A figure does **not** need one icon per box. Prefer one coherent hero illustration plus a few supporting anchors over a row of generic enterprise icons. Match the selected style grammar: - technical vector: restrained monochrome line art; - illustrated modular: rounded hand-drawn line art with at most one semantic accent color per anchor; - print-safe: silhouette, hatch, or geometric markers that survive grayscale. Icons are communication devices, not decorations or evidence. Never add a laboratory robot, wet-lab action, external database, or autonomous capability unless the source material supports it. ## Neural network components | component | prompt phrase | |-----------|--------------| | Transformer block | `small icon of stacked horizontal layers with a curved residual arrow on the right, monochrome line art` | | Attention / MHA | `small attention heatmap grid thumbnail (3x3 cells with varying grey fill) inside or beside the block` | | Self-attention | `small icon: two rows of dots with arrows connecting each dot to every other, monochrome` | | Cross-attention | `small icon: two rows of dots (Q on top, KV below) with arrows crossing between rows` | | MLP / FFN | `small icon: two connected nodes expanding then contracting (fan-out fan-in), monochrome line art` | | Embedding layer | `small icon: a grid of colored squares (token embedding matrix), monochrome` | | Positional encoding | `small sinusoidal waveform icon next to the block, thin line` | | LayerNorm | `small icon: a horizontal bar with a bell curve overlay, monochrome` | | LM head / classifier | `small icon: a single output node connecting to multiple class labels, monochrome` | | Residual connection | `curved solid arrow bypassing sub-layers on the right side, dark grey` | | Skip connection | `dashed curved arrow bypassing layers; add a layer label only when FigureSpec supplies the exact text` | ## Data flow components | component | prompt phrase | |-----------|--------------| | Token sequence | `row of small rounded token squares; render token names only when FigureSpec supplies the exact strings` | | Token embedding lookup | `small matrix grid icon with an arrow pointing to one highlighted row` | | Data pipeline | `small horizontal bar chart thumbnail or data flow icon` | | Checkpoint | `small floppy-disc or save icon, monochrome thin line art` | | Sampling / decoding | `small branching tree icon (beam search), monochrome` | | KV cache | `small stacked memory layers icon, monochrome` | ## Input / output modalities | component | prompt phrase | |-----------|--------------| | Audio waveform | `small audio waveform thumbnail (oscillating line), monochrome` | | Mel spectrogram | `small mel spectrogram thumbnail (horizontal bands with varying brightness), monochrome` | | Image input | `small image frame icon with diagonal cross, monochrome line art` | | 3D / point cloud | `small 3D scatter of dots forming a cube or sphere, monochrome` | | Ray / camera | `small camera frustum icon with rays, monochrome line art` | | Volume rendering | `small icon: dots along a ray with varying opacity (circles sized by weight)` | | MLP (NeRF) | `small fully connected node-layer icon, monochrome; show an exact depth only when sourced` | | Text output | `small document or text lines icon, monochrome` | | Molecular structure | `small molecule/atom graph icon (nodes connected by bonds), monochrome line art` | | Protein / MSA | `small sequence-alignment grid using abstract bars or sourced residue letters only, monochrome` | ## GAN / generative components | component | prompt phrase | |-----------|--------------| | Generator | `small icon: an up-arrow through stacked layers (upsampling), monochrome` | | Discriminator | `small icon: a magnifying glass over a two-way classification marker, monochrome; use class words only when sourced` | | GAN loss | `small icon: two competing arrows (G vs D), monochrome` | | Diffusion / denoising | `small progression from noisy dots to a clean image; use an exact stage count only when sourced` | | VAE / autoencoder | `small icon: funnel narrowing then widening, monochrome` | ## GNN / scientific components | component | prompt phrase | |-----------|--------------| | Graph convolution | `small node-edge graph icon with highlighted neighbors, monochrome` | | Message passing | `small icon: nodes with directional arrows along edges, monochrome` | | Encoder-processor-decoder | `three connected blocks with a graph icon in the center, monochrome` | | Weather grid | `small globe/grid icon with latitude-longitude lines, monochrome` | | RBF / kernel | `small Gaussian bell curve icon, monochrome thin line` | | Coordinate system | `small 3D axes icon (x,y,z), monochrome line art` | ## Agentic scientific workflows and Bayesian optimization These are optional visual metaphors, not default content. Use an entry only when the corresponding component exists in FigureSpec. Any label, variable, candidate count, memory category, laboratory apparatus, or agent embodiment must come from the evidence-backed visible-text/component fields. | concept | prompt phrase | |---|---| | Task / research state | `document with a compact question line and only the sourced state markers, rounded scientific line art` | | Evidence scope | `magnifying glass over a bounded node-edge evidence graph, with a subtle scope ring` | | Provenance manifest | `several cited document slips connected to one manifest sheet; no invented identifiers or body text` | | Typed policy | `decision diamond feeding the sourced number of abstract action tabs, clean line illustration` | | Planner / agent reasoning | `compact decision or reasoning glyph in the selected illustration language; use a robot motif only when the user or reference requests one` | | Cognitive reasoning / LLM query | `small reasoning glyph or requested hand-drawn robot with one approved explanatory question; do not imply a real transcript` | | Uncertainty gauge meter | `uncertainty indicator only when defined in the spec; no invented calibration claim, confidence value or pointer measurement` | | Gating criterion / decision | `decision diamond containing the sourced condition and exact branch labels; never invent a threshold formula` | | 3D GP Response Surface (hero) | `scientific response surface only when declared, using the selected geometry and color grammar; no automatic discrepancy region or coupling formula card` | | 1D Acquisition Function | `1D multi-peak acquisition function curve with coordinate axes, observation dots, and a prominent red peak point x* marked with a magnifying glass pointer` | | Physical / Wet-Lab Experiment | `chemistry laboratory glassware (beakers, flask, microscope) and a computer monitor showing real measurement curves` | | Council / critique | `the supported reviewer roles and assessment outputs; connect only declared interactions, never infer debate, voting or consensus from reviewer count` | | Deterministic harness | `gear aligned with a tabular execution grid, crisp mechanical line art` | | Gaussian Process fit (surrogate) | `mini 2D coordinate plot with arrow axes, a solid fitted mean curve, a same-hue uncertainty ribbon with dashed bounds, and contrasting observation points; bind hues to FigureSpec semantic tokens` | | Initial observations / Warm starts | `small 2D Cartesian coordinate plot with circular observations along a nonlinear trajectory; use only the sourced observation count` | | Candidate pool | `compact structured candidate grid with an abstract header band and highlighted rows; place no generated field names, ranks, variables, or values` | | Working memory | `temporary state card with a short-lived marker; only FigureSpec-provided labels may appear` | | Episodic memory | `ordered event cards along a timeline arrow; only FigureSpec-provided labels may appear` | | Semantic memory | `versioned knowledge or rule cards; only FigureSpec-provided labels may appear` | | Candidate shortlist | `small candidate grid with the sourced number of inputs merging into one selected row` | | Oracle / lookup | `bounded lookup table returning one observation cell; do not imply a database or live service unless sourced` | | Observation commit | `one result card crossing a durable checkpoint line` | | Budget | `small counter or gauge with one increment tick, not a currency symbol` | | Reflection / memory update | `dashed feedback loop from outcome to the declared memory/state component; no agent icon unless sourced` | | Event graph | `short causal chain of typed nodes with directional edges` | | Playbook / rules | `versioned notebook pages with one promoted rule tab` | | Recovery checkpoint | `stacked state cards beside a save milestone, no lock icon` | | Direct exception / stop | `coral report sheet on a short bypass path, used only for exception semantics` | ## Detection / CV components | component | prompt phrase | |-----------|--------------| | CNN backbone | `small icon: stacked feature maps (3 decreasing rectangles), monochrome` | | Object queries | `small row of learned query dots with one highlighted; do not imply a query count unless sourced` | | Bipartite matching | `small icon: two rows of dots with crossing lines (Hungarian matching)` | | Bounding box | `small rectangle with corner markers, monochrome line art` | | Positional encoding (spatial) | `small grid with sinusoidal overlay, monochrome` | ## Status / weight indicators | status | prompt phrase | |--------|--------------| | Frozen / fixed | `dashed border with a neutral status marker; render a word only when FigureSpec provides it` | | Trainable | `solid border with an accent status marker; render a word only when FigureSpec provides it` | | Optional / gated | `dotted border with small gate icon` | ## Usage rules 1. **Anchor the narrative, not every container.** Use anchors for the hero element and major semantic regions; text-only utility subcards are acceptable. 2. **Keep one illustration language.** Do not mix emoji glyphs, stock UI icons, photorealistic assets, and technical line art. 3. **Scale by importance.** A hero mechanism may be a real mini-illustration; secondary anchors remain small. 4. **Bind color semantically.** In illustrated profiles, an anchor may use its region's dark outline plus one accent fill. In classic profiles, keep it monochrome. 5. **Prefer a meaningful shape to a forced icon.** Loops, decision diamonds, graphs, mini-plots, and state cards can carry more information than a generic gear. 6. **Audit capability implications.** An icon must not suggest automation, validation, wet-lab execution, security, or external access that the implementation does not have. -
image-prompt-guide.md 6 KB
# Image Prompt Guide for Academic Figures An image prompt is a rendering adapter for FigureSpec v1. It should preserve evidence-backed topology and a concrete visual grammar while avoiding production instructions that the model may draw as text. For construct/diagnose/revise decisions and feedback routing, first use `prompt-design-logic.md`; this guide elaborates visual choices after those decisions. “More color”, “more information”, and “less clutter” are distinct changes, not interchangeable requests for decoration. ## Before writing After grounding the scientific skeleton, choose or reuse the visual grammar before finalizing composition, marks and text capacity. Follow the style-timing rules in `prompt-design-logic.md`; the prose order below does not postpone style decisions until after layout. Confirm: - the figure's communication goal and hero element; - the closed component and connection lists; - exact visible strings and caption-only material; - the selected style profile or extracted reference grammar; - backend suitability for text density and topology complexity. If the user supplied a reference image, pass that image directly to a capable renderer. The prose prompt describes what to transfer—composition, stroke, fill, typography, spacing, illustration level—and what not to copy—scientific content, labels, branding, or method topology. ## Prompt structure Use this order when it helps; omit slots that add no information. 1. **Image type and communication goal** 2. **Hero composition and semantic regions** 3. **Required components and typed connections** 4. **Visible-text closed list** 5. **Style grammar and semantic color tokens** 6. **Typography, spacing, and publication-scale legibility** 7. **Observed-defect-oriented negative constraints** 8. **Aspect ratio** ### Image type and goal Prefer precise descriptions: - `illustrated modular academic systems framework` - `technical vector network architecture` - `editorial scientific mechanism infographic` - `comparison figure with deterministic plots and a conceptual inset` Do not lead with unsupported venue stereotypes such as “Nature style” or vague taste words such as “premium.” Default to no global canvas title because the figure title normally belongs in the paper's external caption. If the user, FigureSpec, or supplied reference explicitly requires one, render exactly one short title with reserved whitespace and never turn it into a full-width banner. ### Composition Describe proportions, hierarchy, and reading order: - `a research loop occupies the left 40%; two supporting regions stack on the right`; - `a central mechanism is twice the visual weight of the context panels`; - `three responsibility zones are separated by a labeled authority boundary`. Use pipelines only for genuinely sequential executed flows. Loops, storyboards, asymmetric modular collages, layered boundaries, and central mechanisms are first-class layouts. Allow one level of nested subcards when the scientific hierarchy needs it. ### Components and topology Describe only FigureSpec components. State connection endpoints and line semantics exactly, then say that no other inter-module connections should appear. Keep exception and no-budget branches visibly distinct from normal execution. ### Supporting visuals Use an icon, mini-plot, token, formula, dimension, badge, or legend only when it explains sourced content. They are not mandatory decorations. | Visual | Use when | |---|---| | Hero illustration | It communicates the main mechanism or loop faster than boxes | | Line-art anchor | It disambiguates a major semantic role | | Formula/dimension | It is essential, sourced, and readable at final scale | | Legend | Two or more non-obvious encodings require decoding | | Status pill or hatch | A state such as fixed/trainable or advisory/executed must be dual-encoded | ### Style grammar Specify observable decisions instead of a palette name alone: - composition and permitted nesting; - flat/tinted/white fills and shadow policy; - stroke weight, curvature, joins, and arrowheads; - technical, rounded, or hand-drawn typography character; - monochrome, limited-accent, or illustrated line art; - paired region tokens: soft fill, dark outline/title, optional icon accent. Examples: - `illustrated modular: low-saturation region fills, 3px-equivalent same-hue dark outlines, rounded hand-lettered headings, no shadows`; - `technical vector: mostly white modules, restrained tints for groups, 1.5px-equivalent strokes, neutral sans-serif labels`; - `airy UI: white floating panels, restrained soft shadow, color carried by pills and curves`. ### Typography Use a relative hierarchy and final-scale constraint instead of conflicting absolute point sizes: - region headings clearly dominant; - module labels readable at the intended 89 mm or 183 mm width; - secondary notes omitted before they become sub-7pt equivalent; - exact visible strings explicitly listed; - no JSON keys, hex values, `WHITE FILL`, `300 DPI`, or production notes rendered. An image model cannot guarantee exact text. RenderAudit must inspect it; text-heavy figures should use deterministic vector text or a hybrid overlay. ## Common failures 1. Equal-weight boxes erase the scientific focal point. 2. Directory order or JSON order is mistaken for narrative order. 3. Style is reduced to hex values while composition and marks remain generic. 4. Decorative icons, dimensions, legends, and formulas are added without evidence. 5. A reference image is summarized in prose but not supplied to the image tool. 6. Production instructions leak into visible labels. 7. Successful API return is mistaken for publication readiness. 8. An unintended, duplicated, or full-width title banner wastes vertical figure height or conflicts with the paper's LaTeX caption. ## Completion A prompt is ready when it is the shortest lossless rendering brief for FigureSpec, the reference assets are attached appropriately, and RenderAudit has objective checks for topology, text, layout, background, accessibility, and style fidelity. -
json-to-prompt.md 6.7 KB
# FigureSpec to Image Prompt Compilation Compile settled design decisions into rendering instructions without changing scientific content. This is the single compiler. Use `prompt-design-logic.md` first for construction, diagnosis, or revision; do not infer new science during compilation. ## Invariants 1. Preserve every declared component and every edge's endpoints, direction, kind, line semantics and label. 2. Add no unsourced dimensions, formulas, claims, legends, icons or capabilities. A reference supplies style, not evidence for the target method. 3. Only approved `visible_text` and explicitly reconciled component/edge labels are visible. If local label fields and the global inventory disagree, repair the design before compiling. 4. Evidence pointers, caption notes, JSON keys and production metadata are not visible. Hex colors are style instructions, not labels. 5. Reference images remain structured image inputs when supported; prose does not replace reference conditioning. 6. Use compact natural-language paragraphs, without Markdown headings, emphasis, bullet markers or tables around instructions. Do not remove approved scientific symbols merely because they resemble markup. 7. Prompt-only output does not claim rendering or visual validation occurred. A draft brief may precede render-ready FigureSpec; never fabricate output paths to satisfy a prompt-writing request. ## One compilation order This is the prose order, not the design-decision order. Settle the style grammar before finalizing layout; composition and component descriptions must already embody it even though detailed style tokens appear in section 5. If only a content brief exists, return to design before compiling, rather than appending a style slogan to an otherwise frozen prompt. ### 1. Purpose Name the figure type and one communication goal. State the dominant scientific mechanism and any high-risk meaning to avoid. Default to no overall canvas title; when requested, lock exactly one short non-banner title. ### 2. Composition and components Describe the reading order, dominant region, supporting groups and connector channels. Use approximate proportions only when they help, not for every container. Nest cards only when they express real hierarchy; a comparison grid need not have a hero region. Describe optional visual anchors already selected in the spec. A label-only node is valid. A useful hero schematic may replace several repetitive icons. No mandatory icon + mini-plot + math-card bundle. Select visuals by the role they explain, not by the field's stereotypes: | Meaning to communicate | Possible visual, if declared | |---|---| | Propose or reason about an action | small line-art agent with one short decision question | | Independent assessment | reviewer role and bounded advisory output; no invented consensus | | Uncertainty or acquisition | sourced schematic curve or actual deterministic plot | | Representation or transformation | token stream, tensor slices or connection matrix | | Experiment or observation | actual supported apparatus or measured-data symbol | | Memory and provenance | record stack or event graph, distinct from validation | Do not insert a GP surface, threshold test, coupling formula or wet-lab robot merely because the paper concerns optimization. Any illustrative curve without measured data must be identified as schematic in approved labels or caption notes. Quantitative plots use actual data and deterministic plotting. ### 3. Closed topology Translate each declared edge exactly once, identifying source and target by visible label and region when necessary. Include direction, semantic kind, line style and exact label when present. Internal IDs identify checks and are not visible labels unless separately approved. For example: “Draw a solid forward executed arrow from Selection to Experiment, labelled Submit. Draw a dashed advisory arrow from Review to Fusion.” Use this only when those nodes and edges are actually declared. State prohibited shortcuts explicitly where they would change meaning, then “Draw no other inter-module connections.” Spatial proximity never implies an edge. Preserve distinct bidirectional or backward edges without silently converting them to a forward pipeline. ### 4. Visible text Provide a closed list of exact visible strings, grouped by region. Distinguish plot labels and necessary legends from caption-only parameters, evidence and caveats. Never ask for rendered placeholder text or production instructions. A closed inventory is an intent constraint, not an OCR guarantee. ### 5. Visual grammar and semantic color Describe marks, stroke character, fills, typography, spacing, illustration level and shadow policy, then map actual roles to paired soft fill / dark outline-title / optional accent tokens. Add non-color encodings for scientifically important distinctions. Style exclusions must agree with the selected grammar. A declared scientific 3D surface is not “3D chrome”; do not request it and simultaneously forbid all 3D. White is the common default, not an override of a user-approved domain-specific background. ### 6. Defect constraints and geometry End with specific failure prevention: no extra edges, role confusion, duplicate labels, unreadable text, overlap or clipping; add only applicable style exclusions. State aspect ratio and final-scale legibility intent. Physical width and exact point sizes are export/audit metadata, not a guarantee from a raster model. ## Revisions Update the design first. For prompt revision, output a coherent complete new prompt plus a short change/preservation summary; do not accumulate contradictory append-only patches. For an actual image edit, use a bounded edit prompt with the inspected baseline image: observed defect, exact correction, and explicit critical edges/labels/authority boundaries to preserve. “Everything else unchanged” may supplement, but cannot replace, that list. After editing, audit the entire required graph, including edges outside the edited region. ## Length and backend suitability Use the shortest lossless brief. About 180–450 English words often works, but never drop essential edges to meet a word target. Dense labels, precise equations or fragile topology may warrant deterministic SVG/drawio/Typst or hybrid vector text. Preserve the user's chosen backend and current tool policies; if a switch changes the requested deliverable materially, explain and obtain direction. Never claim that prose guarantees exact geometry or typography. ## Preflight Check component/edge coverage, source support, closed visible text, compatible style constraints, reference-input selection and an objective image checklist. Specification validation proves the input contract, not the generated pixels. -
missing-info-policy.md 1 KB
# Missing-Info Policy Shared by all academic-figure skills. Domain skills add only their own cases. ## Rule When evidence is incomplete: ship a **conservative, useful** partial result. Label every claim beyond evidence as `推断` or `待确认`. Prefer placeholders over invention. ## Completeness block (every deliverable) ``` - 已分析材料: ... - 当前输出类型: 完整 / 阶段性 / 局部 / 骨架 - 高置信信息: ... - 待确认信息: ... - 建议补充材料: 1–3 highest-value items ``` ## Stop vs continue | Situation | Action | |-----------|--------| | Core deliverable possible with placeholders | continue | | Zero usable source (no paper, repo, figure type, or image) | stop; list minimum materials | | User asked only this stage | stop after that stage | | Next stage needs material user has not provided | stop; do not invent | ## Invention ban Do not invent modules, losses, dimensions, experiment results, or architecture layers that never appear in the source. Rewrite unknowns as explicit placeholders (`[module_name]`, `R^(?×?)`). -
palettes.md 20.7 KB
# Academic Palettes — Single Source of Truth This file defines **12 classic presets**, three pastel-airy schemes, and paired illustrated semantic-zone tokens. Skills that need hex values or style routing should load this file rather than maintaining private copies. ## Decision order Apply evidence in this order: 1. explicit user colors, style, print, and accessibility requirements 2. supplied reference image grammar 3. hard production constraints such as grayscale output and text contrast 4. figure semantics and visual-zone relationships 5. an existing paper-wide visual system or explicit submission rule 6. conservative default A reference image is the highest-priority inferred style source. Extract composition, panel surfaces, outline strength, shadow treatment, typography character, icon style, nesting depth, density, arrow grammar, and paired fill/outline colors. Match those properties without copying the reference's labels, branded assets, or method content. `module_count` is a density clue only. It does not trigger monochrome. Choose hue count from the number and relationship of semantic zones shown in the figure. | Missing evidence | Conservative default | |---|---| | No reference or style cue, classic technical figure | **Okabe-Ito** | | Explicit airy UI/token figure | **P2 Cool Research** | | Narrative framework or agent/scientific workflow | **I1 Illustrated Zones** | | Accessibility unspecified | colorblind-aware dual encoding and validated text contrast | Always state the branch (`user`, `reference`, `scene`, or `default`) and offer one alternate. ## Style profiles first Palette values only make sense with a surface and line treatment. Select a profile before assigning tokens. | Signals | Profile | Primary skill | Visual grammar | |---|---|---|---| | technical stack, compact network, classic vector, strict print | **`classic-technical`** | `academic-figure-designer` | restrained geometry, fine borders, white or near-white modules, compact sans labels | | airy, token flow, interface-like, soft cards | **`pastel-airy-ui`** | `academic-figure-designer` | white cards, subtle border/shadow, floating pills and tokens, generous whitespace | | hand-drawn academic infographic, modular narrative, agent/scientific workflow, tinted zones | **`illustrated-modular`** | `academic-figure-designer` | asymmetric hero layout, soft semantic-zone fills, strong same-hue outlines, no shadow, one-level subcards, controlled line illustrations | | supplied reference does not fit one preset | **`reference-led`** | `academic-figure-designer` | override defaults with observed grammar; do not assume an illustrated surface | Do not force a supplied reference into a binary classic/pastel label. A coherent figure may combine a classic flat canvas, tinted modular zones, and hand-drawn illustrations. State the observed properties so the combination is intentional rather than a style-word mixture. ### Pastel airy UI schemes Small body text remains neutral `#24323D`. The colored values below are heading accents on white; validate them again before placing small text on a tinted token. | Scheme | Scene | Soft fills | Accessible heading accents on white | |---|---|---|---| | **P1 Warm ML** | playful, teaching, human-centered | `#FFD0D0` `#BBDEFB` `#FFF3C4` `#E1BEE7` `#C8E6C9` | `#A93636` `#146C61` `#6A5ACD` `#2F7430` | | **P2 Cool Research** | calm token-centric research figure | `#B3E5FC` `#C5CAE9` `#CFD8DC` `#B2DFDB` `#D1C4E9` | `#1565C0` `#3949AB` `#006F65` | | **P3 Earthy Warm** | natural or embodied visual direction | `#FFE0B2` `#D7CCC8` `#C8E6C9` `#E0E0E0` `#EFEBE9` | `#6D4C41` `#827717` `#2E7D32` | | **P4 Airy Agentic BO** | surrogate backend, agent decision, charcoal eval anchor | `#FAE8DC` (Peach) `#DBE7FB` (Periwinkle) `#4B5563` (Slate) `#E9E9EC` (Gray) | `#1E293B` `#0F172A` `#FFFFFF` `#334155` | If a reference is present, derive its token pairs instead of snapping every soft figure to the nearest P1–P4 scheme. --- ## I1 Illustrated Zones — paired semantic tokens Each token is a coordinated surface system rather than a standalone accent. `title_text` values meet normal-text contrast against their paired fills; small body text may use neutral `#24323D` throughout. | Token | `soft_fill` | `dark_outline` | `title_text` | `icon_accent` | |---|---|---|---|---| | **I1 Blue** | `#EDF4FB` | `#194166` | `#163E64` | `#2E6B9E` | | **I1 Green** | `#F3FBF0` | `#3B7D23` | `#2F681D` | `#4E8D36` | | **I1 Peach** | `#FBE3D6` | `#A94417` | `#9E3F13` | `#C65A22` | | **I1 Purple** | `#F5ECF5` | `#77206E` | `#65185E` | `#8B3B83` | | **I1 Cyan** | `#DBF3FE` | `#236E96` | `#195876` | `#2F81A8` | | **I1 Gold** | `#FBF1D1` | `#856B1B` | `#66500F` | `#9B7B1C` | | **I1 Coral** | `#FDE8E5` | `#B83A2F` | `#8F2A24` | `#C94D42` | Recommended material treatment: white canvas; 1.5–2.5px zone outlines; 6–14px corner radius scaled to output size; no drop shadows; white or lighter same-hue subcards; dark neutral arrows `#334155` unless the edge itself carries a zone meaning. ## Semantic color binding contract Bind tokens to the roles present in the current paper and retain those bindings across its figures. The mappings below are customizable defaults across different scientific domains: ### 1) Standard Multi-Stage Pipeline & Modular Systems | Domain Role / Stage | Suggested Illustrated Token | Classic/Airy Adaptation | |---|---|---| | **Stage 1: Input / Raw Data / Context** | I1 Green (`#F3FBF0` / `#3B7D23`) | Green accent / data pill | | **Stage 2: Representation / Encoders** | I1 Blue (`#EDF4FB` / `#194166`) | Blue outline / primary container | | **Stage 3: Core Mechanism / Transformation** | I1 Peach (`#FBE3D6` / `#A94417`) | Orange/peach hero zone | | **Stage 4: Optimization / Supervision / Loss** | I1 Purple (`#F5ECF5` / `#77206E`) | Purple accent / dashed constraint | | **Stage 5: Output / Evaluation / Benchmark** | I1 Gold (`#FBF1D1` / `#856B1B`) | Gold heading / output badge | ### 2) Deep Learning & Neural Architectures | Architecture Component | Suggested Illustrated Token | Visual Metaphor / Shape | |---|---|---| | **Raw Input / Embeddings / Tokens** | I1 Green | Structured grid, token pill, or feature map | | **Backbone / Feature Extractor** | I1 Blue | Layered orthogonal blocks or stacked cards | | **Cross-Modal Fusion / Attention Core** | I1 Peach | Heatmap matrix or bipartite connection web | | **Loss Function / Objective / Regularizer** | I1 Purple | Mathematical constraint box or curve | | **Prediction Head / Downstream Task** | I1 Gold | Terminal prediction pill or task badge | ### 3) Agentic & Scientific Interactive Loops | Agentic Role | Suggested Illustrated Token | Visual Metaphor / Shape | |---|---|---| | **Reasoning / Policy / Planner** | I1 Blue | Decision glyph, thought bubble, or planning box | | **Evidence / Context / Observation** | I1 Green | Document icon, coordinate plot, or context card | | **Deterministic Harness / Tool Execution**| I1 Peach | Solid process container or simulation box | | **Advisory / Feedback / Uncertainty** | I1 Purple | Dashed feedback arrow or advisory pill | | **Memory / Storage / Provenance** | I1 Cyan | Network graph or database/checkpoint cylinder | | **Final Output / Report** | I1 Gold | Formatted report card or badge | | **Exception / Guardrail / Stop** | I1 Coral | Warning badge or coral STOP boundary | ### 4) Dual-Fidelity & Bayesian Optimization Loops | Optimization Role | Suggested Illustrated Token | Visual Metaphor / Shape | |---|---|---| | **High-Fidelity / Real-World Experiment / Discrepancy** | I1 Coral (`#FDE8E5` / `#B83A2F`) | Laboratory glassware, oscilloscope/monitor, focused residual peak $\mathcal{X}_R^*$ | | **Low-Fidelity / LLM Prior / Global Surrogate** | I1 Blue (`#EDF4FB` / `#194166`) | Electronic brain, prompt balloon, 3D smooth GP surface | | **Candidate Selection / Acquisition Function** | I1 Peach (`#FBE3D6` / `#A94417`) | 1D search curve, peak marker $x^*$, candidate generator table | | **Gating Criterion / Adaptive Decision** | Decision Diamond (Neutral/Red/Green) | Diamond node $p_\Delta < \tau$, green checkmark / red cross status badges | | **Prior Domain Knowledge / Constraints** | I1 Green / Slate (`#F3FBF0` / `#3B7D23`) | Literature stack, coordinate scatter plot, constraint box | Repeated roles reuse a token; adjacent unrelated zones should also differ by label, geometry, or line style. --- ## Scene → profile and palette decision After explicit user and reference-grammar requirements, apply production constraints and then choose from figure semantics. Venue and domain are suggestions, not guarantees of a single visual style. ### 1) Hard constraints | Constraint | Choose | Alternate | |------------|--------|-----------| | Strict B&W / grayscale print only | **Print-Safe Gray** | Grayscale | | Theory paper, no color budget | **Grayscale** | Print-Safe Gray | | Color-vision accessibility required or prudent | Start from Okabe-Ito / ML TopConf Colorblind / a verified monochrome ramp, then dual-encode and test | Never treat a palette name as proof of accessibility | | Must match existing Matplotlib Tab10 experiment plots | **ML TopConf Tab10** | ML TopConf Colorblind if a11y matters more than match | | Reference has tinted zones and strong outlines | **Illustrated modular + derived pairs** | I1 Illustrated Zones | ### 2) Figure type | Figure type | Prefer | Alternate | Why | |-----------|--------|-----------|-----| | Overall Framework, technical pipeline | Okabe-Ito | ML TopConf Colorblind | clear categorical accents | | Overall Framework, modular narrative | **Illustrated modular + I1** | reference-derived pairs | semantic zones and hierarchy | | Network Architecture | Okabe-Ito or Blue Monochrome | Nature Blue for a restrained single-family stack | structure > decoration | | Module Detail | **Blue Monochrome** | Okabe-Ito | detail density; gray-print friendly | | Comparison / Ablation (few panels) | Purple-Green | Okabe-Ito | category contrast | | Dense multi-panel ablation | **ML TopConf Deep** | Purple-Green | softer multi-hue grid | | Data Behavior (curves / heatmaps / t-SNE) | ML TopConf Colorblind | Okabe-Ito | series/categories stay separable | | Qualitative image grids | Okabe-Ito accents only | Grayscale frames | color on labels, not photo washes | ### 3) Venue and domain constraints Do not map a venue or research domain directly to a palette. Use venue/domain information only when it supplies a concrete production constraint: an official grayscale rule, an existing paper-wide color system, a required plot palette, an accessibility requirement, or a reference figure. Otherwise choose from the content relationships above. “Nature”, “CVPR”, “biology”, “materials”, or “robotics” alone is not a color instruction. ### 4) Vibe words → concrete choice | User says | Family | Palette / scheme | |-----------|--------|------------------| | 高级 / 克制 / 顶刊 | ask for observable traits or use a supplied reference | no venue-name palette default | | 科技感 / 工程感 / 干净 | `classic-technical` | Blue Monochrome or Okabe-Ito | | 柔和 / 空气感 / token 卡片 | `pastel-airy-ui` | P2 | | 手绘 / 叙事 / 模块拼图 / agent 框架 | `illustrated-modular` | I1 or reference-derived pairs | | 活泼 / 教学感 | `pastel-airy-ui` or `illustrated-modular` | P1 or reference-derived pairs | | 自然 / 生物感 | classic Warm Earth, airy P3, or illustrated zones | state accessibility tradeoff | | 不要花 | any coherent profile | reduce active semantic zones; monochrome only if hierarchy remains clear | | 和实验曲线一个色 | `classic-technical` | ML TopConf Tab10 / Colorblind | | 黑白印刷 | `classic-technical` | Print-Safe Gray / Grayscale | --- ## Worked decision recipes | Scenario | Family | Palette | One-line reason | |----------|--------|---------|-----------------| | Technical three-stage method pipeline, no reference | `classic-technical` | Okabe-Ito | categorical accents and compact geometry | | Modular agent/scientific framework, no reference | `illustrated-modular` | I1 Illustrated Zones | semantic zones plus asymmetric hierarchy | | Reference with tinted panels and dark outlines | `reference-led` (observed illustrated grammar) | derived paired tokens | preserve observed visual grammar without assuming every reference is illustrated | | Dense 2×3 ablation grid | `classic-technical` | ML TopConf Deep | multiple comparable panels | | Token-flow explainer with white cards | `pastel-airy-ui` | P2 | token-centric surface grammar | | Continuous single-family mechanism with an explicit restrained-blue preference | `classic-technical` | Nature Blue | user request and hierarchy support one hue family | | Strict B&W journal output | `classic-technical` | Print-Safe Gray | hard print constraint | | Human-centered concept diagram | `pastel-airy-ui` or reference-supported `illustrated-modular` | content/reference dependent | distinguish UI cards from narrative zones | | High-density module detail with no reference | `classic-technical` | Blue Monochrome or accessible custom | detail density and print behavior | | User: 配色随便 | profile from content; Okabe-Ito/P2/I1 | profile default | safe default branch | --- ## Decision checklist (emit with every Palette Decision) 1. Explicit user constraints recorded. 2. Reference grammar summarized, or `no reference supplied`. 3. Canonical profile: `classic-technical` / `pastel-airy-ui` / `illustrated-modular` / `reference-led`. 4. Hard constraint fired? (print / accessibility / match existing plots). 5. Semantic zones and color carriers identified. 6. Primary + alternate named with exact classic colors or paired tokens. 7. Small-text contrast and grayscale dual encoding checked. 8. Branch stated: `user` / `reference` / `scene` / `default`. ## Palette Decision handoff Downstream skills consume: ``` style_profile: <classic-technical | pastel-airy-ui | illustrated-modular | reference-led> style_preset: <named library variant | none> reference_grammar: <summary | none> palette_or_token_set: <name> canvas / body_text / arrow / divider: <hex> semantic_zone_tokens: <role>: {soft_fill: <hex>, dark_outline: <hex>, title_text: <hex>, icon_accent: <hex>} reason: <one line> accessibility: colorblind-aware-tested | needs dual encoding/testing | print-only ``` --- ## 1. Okabe-Ito — default polychrome **Use:** general categorical starting palette when several roles need distinct hues; always add non-color cues and test the rendered figure | role | hex | use | |------|-----|-----| | primary | `#0072B2` | core module borders, section labels | | secondary | `#E69F00` | secondary borders, alternate highlight | | tertiary | `#009E73` | output / result (sparse) | | text | `#333333` | body text | | fill | `#FFFFFF` | canvas / boxes | | section_bg | `#F7F7F7` | region grouping | | border | `#767676` | semantic outline (4.54:1 on white) | | arrow | `#4D4D4D` | arrows / lines | --- ## 2. Blue Monochrome **Use:** module detail; grayscale-friendly journals | role | hex | |------|-----| | primary | `#1565C0` | | secondary | `#42A5F5` | | tertiary | `#90CAF9` | | text | `#212121` | | fill | `#FFFFFF` | | section_bg | `#F5F8FC` | | border | `#607D8B` | | arrow | `#37474F` | --- ## 3. Warm Earth **Use:** explicit earth-toned user/reference direction. Dual-encode; do not infer this palette from a research domain alone. | role | hex | |------|-----| | primary | `#C0392B` | | secondary | `#E67E22` | | tertiary | `#F39C12` | | text | `#2C2C2C` | | fill | `#FFFFFF` | | section_bg | `#FDF6EC` | | border | `#8D6E63` | | arrow | `#5D4037` | --- ## 4. Purple-Green **Use:** two-category comparison or ablation when purple/green fits the labels and reference; never bind a hue to “ours” without the spec | role | hex | |------|-----| | primary | `#6A1B9A` | | secondary | `#2E7D32` | | tertiary | `#AB47BC` | | text | `#1A1A1A` | | fill | `#FFFFFF` | | section_bg | `#F8F5FC` | | border | `#7B1FA2` | | arrow | `#4A148C` | --- ## 5. Grayscale **Use:** explicit grayscale/print-only requirement or a user-selected austere monochrome treatment | role | hex | |------|-----| | primary | `#212121` | | secondary | `#616161` | | tertiary | `#9E9E9E` | | text | `#111111` | | fill | `#FFFFFF` | | section_bg | `#F5F5F5` | | border | `#757575` | | arrow | `#424242` | Distinguish categories by shape / line weight, not hue. --- ## 6. Teal-Coral **Use:** explicit teal/coral two-category contrast. Dual-encode and test for color-vision deficiencies. | role | hex | |------|-----| | primary | `#00695C` | | secondary | `#E64A19` | | tertiary | `#26A69A` | | text | `#212121` | | fill | `#FFFFFF` | | section_bg | `#F0F9F8` | | border | `#00796B` | | arrow | `#004D40` | --- ## 7. ML TopConf Tab10 **Use:** match an existing Matplotlib Tab10 experiment palette; do not choose from venue name alone | role | hex | |------|-----| | primary | `#1F77B4` | | secondary | `#FF7F0E` | | tertiary | `#2CA02C` | | text | `#1F2937` | | fill | `#FFFFFF` | | section_bg | `#F8FAFC` | | border | `#64748B` | | arrow | `#334155` | --- ## 8. ML TopConf Colorblind **Use:** muted colorblind-aware categorical starting palette; still requires dual encoding and rendered-output checks | role | hex | |------|-----| | primary | `#0173B2` | | secondary | `#DE8F05` | | tertiary | `#029E73` | | text | `#1F2937` | | fill | `#FFFFFF` | | section_bg | `#F8FAFC` | | border | `#64748B` | | arrow | `#334155` | --- ## 9. ML TopConf Deep **Use:** multi-panel ablation / dense comparison grids | role | hex | |------|-----| | primary | `#4C72B0` | | secondary | `#DD8452` | | tertiary | `#55A868` | | text | `#1F2937` | | fill | `#FFFFFF` | | section_bg | `#F8FAFC` | | border | `#64748B` | | arrow | `#334155` | --- ## 10. Print-Safe Gray **Use:** explicit strict black-and-white print requirement | role | hex | |------|-----| | primary | `#000000` | | secondary | `#333333` | | tertiary | `#666666` | | text | `#333333` | | fill | `#FFFFFF` | | section_bg | `#F7F7F7` | | border | `#666666` | | arrow | `#4D4D4D` | --- ## 11. Journal Standard **Use:** figures with several verified categories that genuinely need additional accents; not a journal-name default | role | hex | |------|-----| | primary | `#1F77B4` | | secondary | `#FF7F0E` | | tertiary | `#2CA02C` | | accent1 | `#D62728` | | accent2 | `#9467BD` | | accent3 | `#8C564B` | | text | `#1F2937` | | fill | `#FFFFFF` | | section_bg | `#F8FAFC` | | border | `#64748B` | | arrow | `#334155` | Activate only the category colors needed by the current comparison and repeat them consistently. --- ## 12. Nature Blue — restrained monochrome **Use:** a continuous single-family hierarchy, an explicit restrained-blue direction, matching reference grammar, or verified grayscale-friendly output. Do not select it from module count, venue, or domain alone. | role | hex | |------|-----| | primary | `#1B3A5C` | | secondary | `#2E6B9E` | | tertiary | `#5BA0D0` | | gray | `#8EAEC4` | | text | `#333333` | | fill | `#FFFFFF` | | section_bg | `#F7F7F7` | | border | `#5B7890` | | arrow | `#4D4D4D` | --- ## Monochrome vs semantic-zone color | | monochrome (Blue Monochrome / Nature Blue) | semantic-zone color (Okabe-Ito / I1 / custom pairs) | |---|---|---| | visual unity | one hue family | coordinated role-based pairs | | separation | lightness + border + label | fill/outline pair + label + shape | | best when | hierarchy within one conceptual family | readers must scan distinct subsystems or decisions | | print / colorblind | usually robust after value check | robust when dual-encoded and contrast-checked | --- ## Production checks - Preserve explicit user constraints and reference-image grammar unless accessibility or print requirements require an explained adjustment. - Use white, near-white, or soft tinted panel surfaces according to the selected profile; tinted semantic zones are valid academic material. - Use the fewest semantic tokens that keep roles easy to scan, without an arbitrary module-count or three-hue cutoff. - Dual-encode important categories with label, shape, border, icon, or line style in addition to color. - Normal-size text and its actual background should meet a 4.5:1 contrast target; do not use pale accent colors for small text. - Essential outlines, arrow shafts/heads, markers, and focus boundaries should meet a 3:1 graphical contrast target against adjacent colors. Lighter dividers may be decorative only and must not carry meaning. - Avoid unintentional gradients, glossy 3D chrome, photorealistic decoration, and rainbow ordering. Follow a supplied reference when a different treatment is deliberate and legible. - Check the downscaled figure and a grayscale preview before handoff. ## Custom palette minimum ``` style_profile: <name> canvas: #XXXXXX body_text: #XXXXXX arrow: #XXXXXX semantic_zone: soft_fill: #XXXXXX dark_outline: #XXXXXX title_text: #XXXXXX icon_accent: #XXXXXX ``` Add only the semantic zones the figure needs. Validate text contrast, colorblind distinguishability, and grayscale reproduction before handoff. -
prompt-design-cases.md 6.8 KB
# Prompt Design Cases and Transfer Checks 这些案例将真实用户反馈与合成测试分开。用途是复现决策过程,而不是将某篇论文的内容设为默认模板。来源为本次本地对话(2026-09-10 整理,2026-09-14 补充风格时机测试)及旧版设计规范;没有复制未公开论文正文或图片。 ## 1. 手绘风格保留,信息层级重排 真实反馈:“可以要手绘风格的”“信息密度太乱,排得不清晰”,并希望 agent 像手绘机器人在做语言决策。 决策:将风格与结构拆开。手绘轮廓和少量角色插图保留;先重组科学职责和阅读順序,再挑选能解释操作的短气泡。颜色丰富不意味着所有区域同等饱和;信息丰富不意味着每块插入公式和小图。 反例(旧规则风险):每个节点强制放入图标、小图、数学卡,同时要求极简和大量留白。这增加视觉对象,却没有增加可理解的科学关系。 验收:看主区和主路径即可理解协作;次要区域有明确问题分工;没有从参考图迁移不属于目标系统的搜索、融合或检索机制。此案例记录用户需求和设计推导,不声称某张历史输出已通过目检。 ## 2. 内容偏少,与颜色偏少是两次不同修订 真实反馈先要求“信息密度有点少”,之后又要求“色彩调丰富一点”。 决策:第一类修订查证并补充必要状态、条件、产物或反馈;第二类修订只改语义色与强调层级。每次记录允许变化与保留的节点/边/标签,不把两者合成含糊的“make it richer”。 合成测试:基线为 Sample → Filter → Image → Mask。补充已给事实“失败样品转入排除记录”时,可加入有依据的条件与分支;仅要求颜色丰富时,不可新增置信度热图、实验曲线或新模块。 边界:内容正确却太拥挤时优先分层、分图或转 caption。此规则不意味着所有论文图都需要增加密度。 ## 3. 多方评审不自动等于协商式多 agent 真实反馈询问审核、多方讨论 subgraph 和 multi-agent 是否应体现。 决策:查清角色之间是否交换消息、是否有多轮交互、谁产出评估、谁汇合、谁执行。依据独立评审只能画并行建议;有真实交互证据时,才画讨论 subgraph 及其消息边。机器人数量不能证明 multi-agent 协商。 合成对照:两个 reviewer 独立给评分,固定规则聚合,执行器提交实验。可以画两个 reviewer → Aggregator → Executor;不能画 reviewer 之间投票决定真值、直接提交实验。若另给实现证据证明多轮批评/回应,则显式扩充图而不是把无边的头像群称为讨论。 ## 4. 局部 STOP 修复与全图连线回归 历史工作中有“将 STOP 起点移回 Policy”的修订需求。本测试只使用抽象关系;不把未重新查看的历史 rev5/rev6 或其旧审计宣称为真实像素证据。 合成基线期望: | Edge ID | From → To | Meaning / Line | |---|---|---| | e1 | Policy → Proposal | executed / solid | | e2 | Proposal → Review | executed / solid | | e3 | Review → Fusion | advisory / dashed | | e4 | Fusion → Selection | executed / solid | | e5 | Selection → Experiment | executed / solid | | e6 | Policy → STOP | exception / solid | | e7 | STOP → Report | exception / solid | 情境:修复图中错误的 Review → STOP 为 e6,但新图丢失了 e4。 错误验收:“STOP 已修好,因此通过。” 正确验收:e6 pass;e4 fail(缺失);整个新版不通过。即使新 spec 校验通过、其他边漂亮、旧版 audit 全通过,也不能更改结论。图像不可查看时 e4 为 unverified,同样不能通过。 定向 edit prompt 的保留段必须包括 e3、e4、e5 和 e7 的确切端点与线型,而不只说“其他不变”。每次重画后检查全部七条边,并扫描禁止的 Review → Experiment 快捷边。 ## 5. 非 agent 领域迁移 合成输入:“给我写细胞成像流程的英文 prompt。样品过滤后成像,人工标注生成掩码;无定量数据。不用机器人,只要清晰手绘轮廓。” 检查:保留人工作业角色、精确四阶段关系和用户不含机器人的限制;可用样品、滤网、相机、掩码作为语义锚点;不引入 BO、GP、agent、训练指标或测量数值。若原始图到标注另有参考边,也须进入闭合边清单。 这检验规则能否迁移,不构成跨学科质量测量。科学证据来自给定输入,不来自技能对该领域的常识补全。 ## 6. 风格参与构图,受限改色不扩大范围 真实反馈:用户询问应先写内容 prompt 再加风格,还是先确定风格再设计 prompt。 决策:科学骨架明确后、布局定稿前确定视觉语法;构图与组件描述已经体现该语法,后部风格段负责精确表达,而非二次设计。复用已选方向,不增加确认关卡;仅改色时保留布局和科学内容。 2026-09-14 独立 forward-test:两个无父会话上下文的 worker 分别收到技能入口和以下合成请求,未获得预期答案;实际构造/修订 prompt,不改文件或生图。 - **直接 designer 构造:** Sensor → Filter → Classifier → Alert,另有 Filter → Rejected;无数据、无参考图,要求清晰手绘、丰富配色、不要机器人。实际产物在构图段采用轻微不规则轮廓与分离的拒绝分支,保留五节点、四条单向执行边和五个可见标签;没有添加数据、机器人或反向边,也没有等待额外确认。 - **workflow 路由修订:** 已有深海军蓝背景的技术图,Policy → Proposal → Validator → Experiment,Policy → Report 为 STOP 异常分支;只改颜色,锁定其余内容。实际产物仅替换五个节点的填色/轮廓,保留深色底、横向主行、Policy 下方的 Report、四条边的端点与线型、六个可见字符串以及无插图限制。 主 agent 对照原始请求逐项复核上述产物,两项 prompt 行为检查通过。此结果不验证图片条件化、成图风格、灰度可读性或渲染器连线可靠性;后续实际生图仍需独立 RenderAudit。 ## 开发者如何复测 给独立 agent 提供新技能入口、原始请求和最小事实,不给预期答案;要求实际构造/诊断/修订,而不是仅评价文档。至少覆盖 prompt-only、颜色不改拓扑、独立评审权限、局部修复全图回归,以及非 agent 领域。 记录实际产物、缺陷和局限。文档/脚本测试只能证明相应行为或记录契约,不能替代使用真实渲染后端的图片质量测试。修图的成功必须绑定具体图片版本和新目检。 开发方法借鉴 Nuwa 的主题框架提炼和独立测试;来源与限制见 `prompt-design-logic.md`。这些决策启发式不要求运行时安装 Nuwa。 -
prompt-design-logic.md 8.9 KB
# Scientific Figure Prompt Design Logic 此文件负责设计决策;`json-to-prompt.md` 只负责将已确定的 FigureSpec 编译为渲染指令。构造、诊断、修订共用同一套科学约束,不建立第二个编译器。 ## 三个入口与输出边界 | 请求 | 模式 | 输出与停止点 | |---|---|---| | “根据论文构造画图提示词”“只写 prompt” | construct | 简短设计说明、可复制 prompt、待核实项;不调用生图 | | “这个 prompt 为什么画不好”“检查提示词” | diagnose | 问题位置、影响、最小修正建议;不改文件或重画,除非用户要求 | | “按这些反馈改 prompt” | revise | 改动摘要、保留清单、完整新 prompt;只改提示词时不调用生图 | | “画图”“修改这张图” | construct / revise + render | 更新 FigureSpec、内部 prompt、执行与图片审核;不因三个入口多加确认关卡 | 模式是任务范围,不是 FigureSpec 的新字段。仅讨论或写 prompt 时,不虚构 renderer、输出路径、证据或审核通过状态;可先使用设计简报。实际渲染前再补齐并校验 FigureSpec。用户明确索要 prompt 时可展示;用户明确要求不返回 prompt 时继续遵守 `prompt_review: waived`。后续要求查看提示词属于新的展示请求,不自动授权渲染。 ## 先做决定,再写措辞 按依赖关系做下面的决定;简单图可用几句话完成,不必向用户展示内部表单。 1. **图要回答什么。** 写一个读者问题和一句有依据的答案。系列图分别分工:总览回答系统如何协作,机制图解释创新操作、适用条件及输出;这不是强制 Fig1/Fig2 模板。 2. **什么必须出现。** 每个拟新增的节点、条件、反馈、公式或结果说明其证据位置及回答的问题。分为主内容、支撑内容、caption-only;没有证据的机制不因“丰富一点”进入图。 3. **怎样表达,先看哪里。** 先确定下述风格方案,再联合读者问题划分语义区域,分配主次、连线通道及留白。比例只在有助于控制构图时使用,不要求固定面板数、35–50% 主区或多层卡片。 4. **用什么图形解释。** 为真正需要的角色选择视觉锚点;允许只有清晰标签的节点。曲线用于解释关系,机器人用于表达有依据的推理角色;公式、热图、仪表盘、气泡均不是填空装饰。没有数据的概念曲线须明确为示意,不绘造实测数字。 5. **哪些关系绝不能错。** 锁定每条边的 id、from、to、kind、direction、line、label,以及禁止的快捷连线与权限边界。先闭合主路径,再安排辅助反馈;空间邻近不产生边。 6. **哪些文字、颜色承载含义。** 关闭可见文字清单;使用语义色的浅底、深轮廓、局部强调,并以线型、形状或标签作冗余编码。说明最终纸面宽度;删除次要文字或分图,不能仅靠缩小字体解决拥挤。 7. **怎样知道画对了。** 编译前确定必须出现的节点和逐边检查清单。FigureSpec 校验只验证输入契约;每一张新图必须重新目检,图片审核不得继承上一版的 pass。 冲突时优先保留科学含义与权限边界、完整路径和可读性;这不意味着最后才考虑风格。风格应在布局定稿前参与设计,最终 prose prompt 使用编译器的统一顺序,不必复述整个推理过程。 ## 风格在布局定稿前介入 内容简报说明“画什么”,不等于完整 renderer prompt。科学骨架明确后,先确定视觉语法,再共同设计布局、元素形态、文字层级与语义色,最后一次编译。简单图可将这些决定合并完成,不增加必填表单或确认关卡。 - 用户已选风格时直接复用,不重新选型。参考图须先查看,提取轮廓、填色、字体、插图程度、分区与留白;只迁移视觉语法,不迁移其算法、标签或权限。 - 没有参考图时,按内容和用户偏好选择 profile 或现有 style preset,并写出可观察规则,不能只给“手绘”“高级”等形容词。只有名称或文字描述时,不声称已查看参考图;指定且必需的图片不可访问时才请求补附,否则说明使用文字风格方案。 - 让风格影响构图和对象表达:例如手绘方案可使用有语义依据的角色线稿与轻分区;技术方案可强调精确端点与清晰标签。机器人、卡片、非对称构图均非默认要求。跨图复用视觉语法,不强制复制布局。 - prompt 的风格段即使位于后部,构图与组件段也必须已经体现该语法。有可用参考图且渲染器支持时,将图片作为结构化输入传入;文字描述不能冒充图片条件化。 - 仅换风格时,保留科学节点、边、标签及权限,在用户允许范围内调整布局并重新检查文字容量。若用户锁定布局或仅改颜色,不扩大改动;不通过删机制或缩小到不可读来适配风格。 验收分开检查科学拓扑、布局/可读性与风格符合度。prompt 写有风格要求不代表成图已实现;未渲染时不宣称视觉验收通过。 ## 将反馈分解为可控制的改动 | 用户反馈 | 可以改变 | 必须保留 / 验收 | |---|---|---| | 颜色再丰富一些 | 不同语义区域的色相、明暗与局部强调面积 | 节点、连接、可见标签、权限不变;关键关系不只靠颜色 | | 信息密度太少 | 补充有证据的输入状态、触发条件、中间产物、反馈或边界 | 每项新增回答一个原图未回答的问题;不是增加图标数量 | | 太乱、排不清楚 | 重组分区、主次比例、阅读顺序、箭头路由、重复文字 | 保留必要机制与主路径;确需删去科学内容时明说移到哪里 | | 想要手绘机器人 | 轮廓、角色插图、短决策问题气泡 | 仅转移风格;不从参考图复制算法、数字或角色权限 | | 要展示多 agent 讨论 | 有证据的角色、消息交换、评估产物与汇合点 | 只有独立评审时画独立建议,不画辩论/共识;只有实现支持时才画交互式讨论 subgraph | | 只改一个箭头或 STOP 分支 | 精确删除错误边、添加/替换目标边及必要路由 | 显式枚举其他关键边,编辑后全图回归;“其他不变”不足以验收 | 一条反馈可以涉及多个轴,逐项列明。图像中的拟人化对话是说明性文字,不是实际 agent transcript 或新的算法能力。未见证据时不假设 reviewer 可直接执行、提交实验或裁决真值。 ## 诊断:定位原因,不堆形容词 对现有 prompt 指出具体片段、冲突或遗漏及其后果,优先排查: - 科学内容是否来自证据,还是从参考图或通用模板带入; - 主路径是否闭合、端点是否明确,建议与执行是否混淆; - 内容量、色彩丰富度、视觉层级是否被当成同一个问题; - 是否同时要求极简、大量小字、每节点三种插图,或同时要求 3D 又禁止 3D; - 可见文本与制作指令是否混在一起; - 问题来自提示词、输入图片选择,还是后端无法可靠控制精确文字/连线。 只有 prompt 没有图片时,可诊断结构风险,不能声称实际图片缺边或标签错误。只有图片没有源码时,先记录可观察缺陷,对科学正确性保留不确定性。以“问题 → 可见后果/风险 → 最小修正”输出;诊断本身不授权修改文件。 ## 修订:Delta 与 Invariants 保留基线 prompt/spec 及图片版本。给新版本记录本次意图、允许改动、必须保留、禁止新含义、验收项。可直接写在现有工作笔记中,无需新增必填 schema。 样例:将错误的 Review → STOP 删除,新增 Policy → STOP;保留 Review → Fusion(advisory/dashed)、Fusion → Selection(executed/solid)、Selection → Experiment(executed/solid)、STOP → Report(exception),并禁止 Review → Experiment。以上只是一个有这些边的合成案例,不是所有优化算法的默认机制。 先更新结构化设计,再编译完整新 prompt;不要不断把旧 prompt 与互相矛盾的补丁拼接。实际局部图像编辑采用短 edit prompt,包含可观察缺陷、精确改法及上述保留清单,仍需新 spec 和新图片审核。 ## 边界与开发依据 这些是从本项目修图反馈提炼的设计启发式,不是经过跨学科实验验证的普遍定律。参考 `prompt-design-cases.md` 的来源边界和迁移测试。手绘、机器人、丰富配色都是可选择的风格,不是默认强制项。 本次采用 [Nuwa / 女娲](https://github.com/alchaincyf/nuwa-skill)(创建者:[花叔](https://x.com/AlchainHust))的主题框架提炼方法:从触发情境抽取决策、保留反例和局限,并用新情境检验。只基于本地用户反馈和既有规范,不冒称领域共识;运行此技能不需要安装 Nuwa。 -
prompt-templates.md 5.8 KB
# Prompt Scaffolds for Academic Figures Use these as fillable examples, not universal composition requirements. Make decisions using `prompt-design-logic.md`, then follow the single order in `json-to-prompt.md`. Remove unused clauses and all placeholders before rendering. The prose blocks are renderer input; surrounding Markdown is documentation only. ## Construct: compact scientific brief Before filling this scaffold, settle or reuse the style grammar and let it shape composition, visual anchors and text capacity. Its later paragraph records already-made decisions; it is not a post-hoc style patch. See `prompt-design-logic.md` for reference-image and style-only revision handling. ```text Create a [figure type] explaining [one scientific question and supported answer]. Do not imply [important forbidden claim]. The reading order is [order]. Put [main mechanism] in [position], with [supporting context] in [relative positions]. Separate [actual responsibility domains] and reserve [connector channel]. Show [required components and their declared visual anchors]; use plain labelled nodes where illustration adds no meaning. Draw exactly these connections: [source, target, direction, semantic kind, line style, exact edge label for each edge]. Do not draw [high-risk forbidden shortcuts] or any other inter-module connection. Visible text is limited to [exact approved inventory grouped by region]. Keep [parameters, evidence and long explanation] in the external caption, not on the canvas. Use [observable marks, fills, stroke, typography and illustration grammar]. Map [actual semantic role] to [soft fill, dark outline/title, accent]; distinguish [critical classes] with [line/shape/label cue] as well as color. [Applicable exclusions and legibility constraints]. Aspect ratio [ratio]. ``` A prompt-only request ends with this brief and known uncertainties; it does not require a renderer call or an invented filesystem output path. ## Choose a composition that answers the question | Scientific story | Candidate composition | |---|---| | Repeated optimization or research cycle | hero loop or storyboard | | Separate responsibility/authority domains | asymmetric modules or layered boundary | | Truly sequential execution | pipeline | | Central operation with supporting context | central mechanism with satellites | | Alternatives or interventions | balanced comparison grid | | Quantitative behavior | deterministic plots from underlying data | Approximate area allocation can help a crowded design, but no layout, panel ratio or icon count is mandatory. ## Illustrated agent / multi-agent region Use only when roles and their interactions are supported. Replace the relevant component clause in the construct brief: ```text Represent [actual proposing role] as a small hand-drawn robot beside [its decision output], with the short illustrative question [approved text]. Show [supported reviewer roles] producing [bounded assessments]. Use [independent advisory arrows, or evidenced message-exchange edges] into [declared consumer]. Keep [actual executor] visually separate. These illustrative speech bubbles are explanatory, not a transcript. Do not imply that reviewers execute experiments or manufacture observations. ``` A request for more agents is not evidence of debate, voting or consensus. A subgraph shows interactions only when those interactions exist; otherwise draw distinct evaluators and their actual outputs. ## Mechanism detail Use this purpose/composition clause when a system overview already exists: ```text Explain where [specific contribution] operates: [its input/state], [operation or eligibility condition], and [result consumed downstream]. Arrange these as [evidence-supported layout], keeping the operation dominant. Include a context inset only if needed to locate the mechanism within the full system. Do not repeat the entire overview or add unsourced performance claims. ``` Follow with the same full edge inventory, visible text and visual grammar. There is no fixed Fig2 panel count. ## Diagnose: user-facing response shape This is analysis, not a renderer prompt: - Problem: the exact conflicting or missing clause. - Consequence: a risk inferred from prompt text, or a defect observed in a specified image. - Minimal correction: the smallest design/wording/backend adjustment. - Preserved meaning: nodes, edges, labels or authority that must not change. No image means no claim of observed pixel defects. Do not alter files or generate a replacement merely because diagnosis is complete. ## Revise prompt: full replacement First state “Changed: [allowed deltas]. Preserved: [critical nodes, edges, text and boundaries]. Unverified: [remaining evidence gaps].” Then provide a complete updated construct brief, not just appended instructions. For color-only changes, compare component/connection/label inventories against the baseline and leave them identical. ## Edit image: local repair with global preservation ```text Edit the supplied baseline image [revision]. The observed defect is [specific visible defect]. Remove [incorrect item] and replace it with [exact corrected item and route]. Preserve these critical connections: [full endpoint, kind, direction and line list], these labels [inventory], and these authority boundaries [list]. Keep [unaffected composition and style]. Do not introduce [forbidden relation]. Save a new revision; do not recreate unrelated regions. ``` Version naming and saving are execution instructions, not canvas text. Reinspect all required edges in the new image; successful repair of the target alone is not a passing audit. ## Data figures and precise text For measured curves, heatmaps, tables or mathematical plots, use actual data and a deterministic renderer. Image generation may supply a conceptual illustration, but must not invent numerical results. Request an alternate text/vector backend only within user authorization and active tool policy. -
render-audit.md 11 KB
# Render Audit Protocol Use this protocol after every generated academic figure and after each targeted edit. A successful image-generation API response is not evidence that the figure is correct. Inspect the image at original resolution and compare it with the confirmed FigureSpec, source evidence, and any reference image. ## Inputs and output Required inputs: - the validated `academic-figure/FigureSpec@1` object; - the rendered image at an absolute local path; - source figure plan and evidence locations; - reference images when `style_profile` is `reference-led`. Emit a JSON-compatible audit: ```text schema: academic-figure/RenderAudit@2 figure_id, render_revision, image_path (absolute) image_sha256, spec_sha256 (lowercase SHA-256 of exact file bytes) spec_validation: {status: pass|fail|unverified} image_inspection: {status: pass|fail|unverified, evidence} nodes[]: {id, status: pass|fail|unverified, evidence} edges[]: {id, from, to, kind, direction, line, label, status: pass|fail|unverified, evidence} checks: semantic_topology, visible_text, background, layout, style_fidelity, accessibility (each check is {status: pass|fail|unverified, evidence}) pass: true|false defects[]: {check, severity, observed, expected, evidence, edit_instruction} targeted_edit: string|null semantic_edits_used: 0|1|2 semantic_edits_remaining: 2|1|0 residual_risks[] ``` ## Revision binding and complete ledgers New audits use RenderAudit@2. Keep legacy @1 records for history, but do not upgrade their booleans mechanically into observed @2 results. Bind each audit to one actual image and one actual FigureSpec by path, revision, and raw-file SHA-256. Finish any export/metadata transformation before binding the delivered file, then inspect that exact final file. A new file or changed spec needs a new audit; do not copy forward a previous image's pass. FigureSpec validation and actual image inspection are independent. Record their statuses separately. If the image cannot be opened, or an arrowhead is too ambiguous to identify, use `unverified`, not a guessed `pass`. Evidence describes what was inspected, including region or endpoints; “spec valid” is not visual evidence. Image inspection status says whether inspection was performed; defects found during inspection belong in the individual check statuses. Derive the complete node and edge ledger from the spec, not from what is easiest to see. Cover every component and every connection exactly once. Use declared edge IDs; for a legacy connection without an ID, use its stable one-based position as `edge_001`, `edge_002`, etc. Copy from/to/kind/direction/line/label exactly; for omitted direction/line use `unspecified`, and omitted label is an empty string. Semantic kind remains required. This does not authorize rendering a scientifically ambiguous spec. Check the image against the ledger, then scan the image for extra edges and forbidden shortcuts; a required-edge ledger alone cannot detect invented arrows. Record that second scan and authority-boundary checks under semantic_topology. Record the actual text-inventory and final-size inspection under the relevant checks. Reset all statuses to unverified for every new image, including style-only and single-arrow edits, and recheck all required edges outside the edited region. For the bundled record validator (it does NOT inspect pixels), run: ```bash python3 <workflow>/scripts/validate_render_audit.py \ --spec <spec.json> --image <image.png> <audit.json> ``` Exit 0 means the bound record is complete and all asserted statuses pass; exit 1 means a valid record is failed/unverified; exit 2 means malformed, incomplete or mismatched evidence, including a stale digest or misleading aggregate pass. When workflow's script is not installed, perform the same ledger checks manually and state that record validation was manual. Never call this script's exit 0 proof of scientific accuracy or image quality: it cannot verify the truthfulness of a human/model's visual assertions. A legal top-level `pass: true` requires all node/edge/check statuses, spec validation and image inspection to pass, with no critical or major defect. Any fail or unverified status blocks acceptance. A complete record of a failed image is useful and must remain failed. `severity` is `critical`, `major`, or `minor`. A critical or major defect makes the audit fail. Minor defects may pass only when they do not change scientific meaning, legibility, accessibility, or the requested visual identity. ## 1. Semantic topology Treat the FigureSpec component and connection lists as a directed graph. - Every required component appears exactly once unless duplication is explicitly specified as a repeated stage. - Every rendered arrow has the correct source, target, direction, kind, and label. - Required branches, loops, authority boundaries, budget effects, and persistence paths are present. - Forbidden components, connections, causal implications, performance claims, and copied scientific content are absent. - Advisory, executed, feedback, persistence, and exception paths remain visually distinguishable according to the spec. Any missing, invented, reversed, or merged scientific edge is a **critical** defect. Do not approve a visually attractive but semantically incorrect render. ## 2. Visible text Compare the image against the complete `visible_text` inventory, using visual inspection and OCR when available. - Every required string is present, spelled correctly, and assigned to the right component or connection. - No JSON keys, prompt instructions, hex codes, production notes (`WHITE FILL`, `300 DPI`, stroke widths), watermarks, or unexplained text are visible. - No duplicated, truncated, fused, hallucinated, or illegible labels remain. - Mathematical symbols, identifiers, capitalization, and branch labels preserve their specified meaning. - Text remains readable at the intended 89 mm or 183 mm publication width, not merely when zoomed to the generation resolution. Scientific text errors are critical. Optional secondary-label loss is major when it damages interpretation and minor only when the FigureSpec marks it optional. ## 3. Background and artifact integrity - Canvas dimensions match the requested aspect ratio within raster rounding. - The background is the specified solid color; when white is required, corner and inter-panel pixels are opaque `#FFFFFF`, not transparent, gray, or black. - No accidental alpha channel, crop, border, compression damage, checkerboard, watermark, or model signature is present. - Metadata and provenance cleanliness: sanitize and strip all C2PA manifests, JUMBF markers, EXIF, and AI generation metadata using `clean_image_metadata.py` before final delivery. - The file extension matches the encoded media type and the image opens normally. A background or opacity that differs from the FigureSpec, a wrong crop, or a wrong aspect ratio is a major defect. A file that cannot be decoded is critical. ## 4. Layout and publication-scale legibility - Components follow the planned reading order, grouping, hierarchy, focal point, and relative emphasis. - Boxes, illustrations, labels, legends, and arrowheads do not overlap or collide. - Connections do not ambiguously cross nodes or terminate in empty space. - Margins and whitespace are intentional; the figure is neither an empty template nor a uniformly dense wall of boxes. - Primary information survives a thumbnail/publication-width check; secondary detail may recede but must not become visual noise. - Repeated elements align consistently while semantic exceptions remain salient. Overlap that hides meaning or an ambiguous connector is major. Minor alignment variation is minor only when the intended reading order stays unambiguous. ## 5. Style fidelity For a built-in profile, check the profile's composition, marks, strokes, fills, typography, spacing, motifs, and emphasis—not just its named colors. For a supplied reference, compare transferable visual grammar while keeping the new method's content and topology independent. - Composition and visual hierarchy match the selected profile or reference. - Palette colors have the specified semantic roles and relative area; do not wash every region with equally saturated color. - Stroke language, arrow curvature, illustration level, panel treatment, corner geometry, typography character, and whitespace match the intended family. - Absent traits from the reference stay absent: do not add enterprise swimlanes, heavy dark borders, gradients, shadows, 3-D chrome, clip art, or generic robot motifs unless the profile calls for them. - A reference's labels, metrics, branding, scientific objects, and topology are not copied merely to imitate its appearance. A palette match with the wrong composition or mark language does **not** pass style fidelity. Clearly landing in the wrong style family is major. ## 6. Accessibility and print behavior - Normal-size text has at least 4.5:1 contrast against its actual background; large text has at least 3:1. - Essential outlines, arrows, markers, and focus boundaries have at least 3:1 graphical contrast against adjacent colors; pale decorative dividers do not carry semantic meaning. - Critical distinctions use color plus a second cue such as label, shape, marker, hatching, or line style. - Simulated protanopia, deuteranopia, and tritanopia views preserve required distinctions when a simulation tool is available. - A grayscale preview preserves topology, grouping, and exception branches. - Thin strokes, pale tokens, and small type remain discernible at publication size. Record the measured foreground/background pairs when contrast tooling is available. Never infer accessibility from a palette name alone. ## Targeted-edit policy The initial render may receive **at most two targeted semantic visual edits**. A single retry for a transient API/transport failure does not consume this budget because it did not attempt to change the image semantics. 1. Audit the initial render and rank defects by semantic risk. 2. If it fails, write one bounded edit instruction containing only the observed defects, their exact expected replacements, and an explicit list of critical nodes, edge endpoints/directions/types, visible labels and authority boundaries to preserve. “Keep everything else” alone is not a preservation contract. 3. Inspect the edited image and emit a newly bound audit. Recheck the full required edge ledger, not just the repaired connector; do not assume an edit preserved topology or text. 4. If needed, perform one final targeted edit, then audit again. 5. After two targeted edits, stop. Deliver the best valid artifact only if all critical and major checks pass; otherwise mark the render incomplete and report residual defects instead of silently accepting it or starting an unbounded loop. Do not use a whole-image style rewrite to repair one spelling error or connector. Conversely, do not patch isolated colors when the audit shows the entire style family or composition is wrong; use the first targeted edit to correct that bounded systemic defect and preserve grounded content.
-
-
scripts
-
clean_image_metadata.py 5.8 KB
#!/usr/bin/env python3 """Sanitize image metadata and strip C2PA, EXIF, XMP, and invisible provenance markers. This module provides standalone CLI and importable utilities to strip all generative AI provenance metadata (C2PA, JUMBF, EXIF, XMP, IPTC, Adobe markers, and trailing payloads) from rendered academic figures, ensuring pristine, publication-ready deliverables. """ from __future__ import annotations import argparse import os import sys from pathlib import Path from typing import Optional, Tuple from PIL import Image def strip_image_metadata( input_path: str | Path, output_path: Optional[str | Path] = None, output_format: Optional[str] = None, quality: int = 95, ) -> Tuple[bool, int, int]: """Strip all metadata (C2PA, EXIF, XMP, IPTC) from an image file. Args: input_path: Path to the source image. output_path: Destination path. If None, overwrites input_path atomically. output_format: Desired format ('PNG', 'JPEG', etc.). Defaults to source format. quality: JPEG compression quality (1-100) if saving as JPEG. Default 95. Returns: Tuple of (success: bool, original_bytes: int, cleaned_bytes: int) """ src = Path(input_path).resolve() if not src.is_file(): raise FileNotFoundError(f"Image not found: {src}") dst = Path(output_path).resolve() if output_path else src original_size = src.stat().st_size with Image.open(src) as img: img_format = output_format.upper() if output_format else (img.format or "PNG").upper() # Normalize modes if img_format in ("JPEG", "JPG"): if img.mode in ("RGBA", "LA", "P"): # Composite onto opaque white background bg = Image.new("RGB", img.size, (255, 255, 255)) if img.mode == "RGBA": bg.paste(img, mask=img.split()[3]) else: bg.paste(img.convert("RGBA"), mask=img.convert("RGBA").split()[3]) clean_img = bg elif img.mode != "RGB": clean_img = img.convert("RGB") else: clean_img = Image.new("RGB", img.size) clean_img.paste(img) else: # PNG or other lossless formats target_mode = "RGBA" if img.mode in ("RGBA", "LA", "P") else "RGB" clean_img = Image.new(target_mode, img.size) clean_img.paste(img) # Write to temporary file first for atomic overwrite dst.parent.mkdir(parents=True, exist_ok=True) tmp_dst = dst.with_name(f".tmp_clean_{dst.name}") try: if img_format in ("JPEG", "JPG"): clean_img.save( tmp_dst, format="JPEG", quality=quality, subsampling=0, optimize=True, ) elif img_format == "PNG": clean_img.save( tmp_dst, format="PNG", optimize=True, ) elif img_format == "WEBP": clean_img.save( tmp_dst, format="WEBP", lossless=True, quality=100, ) else: clean_img.save(tmp_dst, format=img_format) tmp_dst.replace(dst) finally: if tmp_dst.exists(): tmp_dst.unlink() cleaned_size = dst.stat().st_size return True, original_size, cleaned_size def batch_clean_directory( directory_path: str | Path, recursive: bool = True, extensions: Tuple[str, ...] = (".png", ".jpg", ".jpeg", ".webp"), ) -> int: """Batch clean metadata for all supported images in a directory. Returns the count of processed images. """ root = Path(directory_path).resolve() if not root.is_dir(): raise NotADirectoryError(f"Directory not found: {root}") files = root.rglob("*") if recursive else root.glob("*") count = 0 for file_path in files: if file_path.is_file() and file_path.suffix.lower() in extensions: try: strip_image_metadata(file_path) count += 1 except Exception as err: print(f"[Warning] Failed to clean {file_path}: {err}", file=sys.stderr) return count def main() -> None: parser = argparse.ArgumentParser( description="Sanitize image metadata, stripping C2PA, EXIF, and AI provenance markers." ) parser.add_argument("target", help="Path to image file or directory") parser.add_argument( "-o", "--output", help="Output path (for single image; defaults to in-place replacement)" ) parser.add_argument( "--format", choices=["PNG", "JPEG", "WEBP"], help="Convert to specific format" ) parser.add_argument( "-q", "--quality", type=int, default=95, help="JPEG quality (default: 95)" ) parser.add_argument( "-r", "--recursive", action="store_true", default=True, help="Recurse into subdirectories" ) args = parser.parse_args() target_path = Path(args.target).resolve() if target_path.is_file(): success, orig, clean = strip_image_metadata( target_path, output_path=args.output, output_format=args.format, quality=args.quality, ) print( f"✅ Cleaned {target_path.name}: {orig:,} bytes -> {clean:,} bytes " f"(stripped {max(0, orig - clean):,} bytes metadata)" ) elif target_path.is_dir(): count = batch_clean_directory(target_path, recursive=args.recursive) print(f"✅ Batch cleaned {count} images in {target_path}") else: print(f"❌ Target path not found: {target_path}", file=sys.stderr) sys.exit(1) if __name__ == "__main__": main() -
validate_figure_spec.py 43.3 KB
#!/usr/bin/env python3 """Validate Academic FigureSpec JSON without third-party dependencies. Default mode accepts historical benchmark specs and emits migration warnings. ``--strict-v1`` requires the versioned ``academic-figure/FigureSpec@1`` handoff. JSON Schema handles local field shapes; this validator additionally enforces cross-field invariants: unique component ids, valid connection endpoints, known style profiles, group membership, and absolute artifact paths. """ from __future__ import annotations import argparse import hashlib import json import re import stat from dataclasses import asdict, dataclass, field from pathlib import Path, PureWindowsPath from typing import Any, Iterable SCHEMA_V1 = "academic-figure/FigureSpec@1" ID_PATTERN = re.compile(r"^[A-Za-z][A-Za-z0-9._-]*$") ASPECT_RATIOS = frozenset({"16:9", "3:2", "4:3", "1:1"}) CONNECTION_DIRECTIONS = frozenset({"forward", "backward", "bidirectional"}) PROMPT_REVIEW_STATES = frozenset({"requested", "confirmed", "waived"}) VISIBLE_TEXT_PRIORITIES = frozenset({"primary", "secondary", "optional"}) STYLE_SOURCES = frozenset({"user", "reference", "scene", "default"}) SHA256_PATTERN = re.compile(r"^[0-9a-f]{64}$") LAYOUT_COMPOSITIONS = frozenset( { "pipeline", "loop", "storyboard", "layered_boundary", "central_mechanism", "modular_collage", "comparison_grid", "custom", } ) STYLE_PROFILE_IDS = frozenset( { "classic-technical", "modern-technical-vector", "pastel-airy-ui", "illustrated-modular", "reference-led", } ) STYLE_PROFILE_ALIASES = { "Classic technical": "classic-technical", "Pastel airy UI": "pastel-airy-ui", "Illustrated modular": "illustrated-modular", "Reference-led": "reference-led", "classic-academic-border": "classic-technical", "modern-technical-vector": "classic-technical", "modern-pastel-airy": "pastel-airy-ui", "nature-blue-minimal": "classic-technical", "okabe-ito-universal": "classic-technical", "purple-green-comparison": "classic-technical", "print-safe-grayscale": "classic-technical", "reference-derived": "reference-led", "custom": "reference-led", "经典学术框线风": "classic-technical", "现代前沿技术框线风": "classic-technical", "现代柔彩空气风": "pastel-airy-ui", "有色语义分区图示风": "illustrated-modular", "编辑手绘模块风": "illustrated-modular", "顶刊蓝调极简风": "classic-technical", "通用色盲友好风": "classic-technical", "对比消融实验风": "classic-technical", "严谨黑白印刷风": "classic-technical", "双保真度引导闭环风": "illustrated-modular", "dual-fidelity-loop": "illustrated-modular", "Dual fidelity loop": "illustrated-modular", "Classic academic": "classic-technical", "Pastel airy": "pastel-airy-ui", } V1_REQUIRED = ( "schema", "figure_id", "plan_revision", "sources", "prompt", "aspect_ratio", "final_width_mm", "visible_text", "layout", "topology", "style_profile", "style_grammar", "semantic_color_roles", "reference_images", "must_not_claim", "forbidden_connections", "negative_constraints", "prompt_review", "workspace_root", "output_path", ) @dataclass(frozen=True) class Diagnostic: severity: str code: str path: str message: str @dataclass class ValidationReport: source: str = "<memory>" mode: str = "compatible" diagnostics: list[Diagnostic] = field(default_factory=list) def error(self, code: str, path: str, message: str) -> None: self.diagnostics.append(Diagnostic("error", code, path, message)) def warning(self, code: str, path: str, message: str) -> None: self.diagnostics.append(Diagnostic("warning", code, path, message)) @property def errors(self) -> list[Diagnostic]: return [item for item in self.diagnostics if item.severity == "error"] @property def warnings(self) -> list[Diagnostic]: return [item for item in self.diagnostics if item.severity == "warning"] @property def ok(self) -> bool: return not self.errors def to_dict(self) -> dict[str, Any]: return { "source": self.source, "mode": self.mode, "ok": self.ok, "errors": len(self.errors), "warnings": len(self.warnings), "diagnostics": [asdict(item) for item in self.diagnostics], } def _is_absolute_path(value: str) -> bool: return Path(value).is_absolute() or PureWindowsPath(value).is_absolute() def _is_within_path(value: str, root: str) -> bool: """Return whether an absolute output path is contained by an absolute root.""" windows_value = PureWindowsPath(value) windows_root = PureWindowsPath(root) if windows_value.is_absolute() or windows_root.is_absolute(): if not (windows_value.is_absolute() and windows_root.is_absolute()): return False try: windows_value.relative_to(windows_root) except ValueError: return False return True try: Path(value).resolve(strict=False).relative_to(Path(root).resolve(strict=False)) except (OSError, RuntimeError, ValueError): return False return True def _resolved_native_path(value: str | Path) -> Path: """Return a native absolute path without requiring the leaf to exist.""" return Path(value).expanduser().resolve(strict=False) def _has_symlink_component(path: Path) -> bool: """Return whether an existing component of *path* is a symbolic link.""" candidate = path if path.is_absolute() else path.absolute() for component in (candidate, *candidate.parents): try: if component.is_symlink(): return True except (OSError, RuntimeError, ValueError): # Filesystem failures are handled by later existence/type checks. # They must not turn malformed or racy input into a crash. continue return False def _is_id(value: Any) -> bool: return isinstance(value, str) and bool(ID_PATTERN.fullmatch(value)) def _expect_type( report: ValidationReport, value: Any, expected: type | tuple[type, ...], path: str, label: str, ) -> bool: if isinstance(value, expected): return True names = ( "/".join(item.__name__ for item in expected) if isinstance(expected, tuple) else expected.__name__ ) report.error("type.invalid", path, f"{label} must be {names}") return False def _style_profile_value(spec: dict[str, Any]) -> tuple[Any, str]: if "style_profile" in spec: return spec["style_profile"], "$.style_profile" style = spec.get("style") if isinstance(style, dict): if "profile" in style: return style["profile"], "$.style.profile" if "name" in style: return style["name"], "$.style.name" return None, "$.style_profile" def _validate_style_profile( report: ValidationReport, spec: dict[str, Any], *, required: bool ) -> str | None: value, path = _style_profile_value(spec) if value is None: if required: report.error("style_profile.required", path, "strict FigureSpec v1 requires a style profile") else: report.warning( "legacy.style_profile_missing", path, "legacy spec has no machine-checkable style profile", ) return None if isinstance(value, dict): value = value.get("id") path += ".id" if not isinstance(value, str): report.error("style_profile.type", path, "style profile must be a string or an object with string id") return None canonical = STYLE_PROFILE_ALIASES.get(value, value) if canonical not in STYLE_PROFILE_IDS: allowed = ", ".join(sorted(STYLE_PROFILE_IDS)) report.error( "style_profile.invalid", path, f"unknown style profile {value!r}; expected one of: {allowed}", ) return None if value in STYLE_PROFILE_ALIASES: message = f"use canonical profile id {canonical!r} in FigureSpec v1" if required: report.error("style_profile.noncanonical", path, message) else: report.warning("style_profile.alias", path, message) return canonical def _extract_topology( spec: dict[str, Any], *, v1: bool ) -> tuple[Any, Any, Any, str]: topology = spec.get("topology") if isinstance(topology, dict): return ( topology.get("components"), topology.get("connections"), topology.get("groups", []), "$.topology", ) if "content_blocks" in spec: visual = spec.get("visual_elements") connections = visual.get("connections") if isinstance(visual, dict) else None return spec.get("content_blocks"), connections, [], "$.content_blocks" if "components" in spec or "connections" in spec: return spec.get("components"), spec.get("connections"), spec.get("groups", []), "$" if "layout_and_content_blocks" in spec: return spec.get("layout_and_content_blocks"), None, [], "$.layout_and_content_blocks" return None, None, None, "$.topology" if v1 else "$" def _validate_topology(report: ValidationReport, spec: dict[str, Any], *, v1: bool) -> None: components, connections, groups, base = _extract_topology(spec, v1=v1) if components is None: if v1: report.error("topology.components_required", "$.topology.components", "components list is required") else: report.warning("legacy.topology_missing", base, "legacy spec has no machine-checkable components") return if not isinstance(components, list): report.error("topology.components_type", f"{base}.components" if base == "$.topology" else base, "components must be a list") return if v1 and not components: report.error("topology.components_empty", "$.topology.components", "strict FigureSpec v1 needs at least one component") component_ids: set[str] = set() component_group_refs: list[tuple[str, str]] = [] id_path = "$.topology.components" if base == "$.topology" else base missing_ids = 0 for index, component in enumerate(components): path = f"{id_path}[{index}]" if not isinstance(component, dict): report.error("component.type", path, "component must be an object") continue component_id = component.get("id") if component_id is None: missing_ids += 1 if v1 or connections: report.error("component.id_required", f"{path}.id", "component id is required") continue if not _is_id(component_id): report.error( "component.id_invalid", f"{path}.id", "component id must start with a letter and contain only letters, digits, '.', '_' or '-'", ) continue if component_id in component_ids: report.error("component.id_duplicate", f"{path}.id", f"duplicate component id {component_id!r}") component_ids.add(component_id) if v1 and not ( isinstance(component.get("label"), str) and component["label"].strip() ): report.error("component.label_required", f"{path}.label", "strict v1 component requires a label") group_id = component.get("group_id") if group_id is not None: if not _is_id(group_id): report.error( "component.group_id_invalid", f"{path}.group_id", "component group_id must be a valid id", ) else: component_group_refs.append((f"{path}.group_id", group_id)) if missing_ids and not v1 and not connections: report.warning( "legacy.component_ids_missing", id_path, f"{missing_ids} legacy component(s) have no ids; endpoints cannot be checked", ) if connections is None: if v1: report.error("topology.connections_required", "$.topology.connections", "connections list is required") else: report.warning( "legacy.connections_unstructured", "$", "legacy prose flow cannot be checked for endpoint integrity", ) connections = [] elif not isinstance(connections, list): report.error("topology.connections_type", "$.topology.connections", "connections must be a list") connections = [] connection_ids: set[str] = set() for index, connection in enumerate(connections): path = f"$.topology.connections[{index}]" if base == "$.topology" else f"$.connections[{index}]" if not isinstance(connection, dict): report.error("connection.type", path, "connection must be an object") continue connection_id = connection.get("id") if connection_id is not None: if not _is_id(connection_id): report.error("connection.id_invalid", f"{path}.id", "connection id has invalid syntax") elif connection_id in connection_ids: report.error("connection.id_duplicate", f"{path}.id", f"duplicate connection id {connection_id!r}") else: connection_ids.add(connection_id) source_key = "from" if "from" in connection else "source_id" target_key = "to" if "to" in connection else "target_id" source = connection.get(source_key) target = connection.get(target_key) for key, endpoint in ((source_key, source), (target_key, target)): endpoint_path = f"{path}.{key}" if not _is_id(endpoint): report.error("connection.endpoint_invalid", endpoint_path, "connection endpoint must be a valid component id") elif endpoint not in component_ids: report.error( "connection.endpoint_unknown", endpoint_path, f"connection endpoint {endpoint!r} does not name a declared component", ) if v1 and not ( isinstance(connection.get("kind"), str) and connection["kind"].strip() ): report.error( "connection.kind_required", f"{path}.kind", "strict v1 connection requires a non-empty kind", ) label = connection.get("label") if "label" in connection and not isinstance(label, str): report.error( "connection.label_type", f"{path}.label", "connection label must be a string", ) direction = connection.get("direction") if v1 and direction is None: report.error( "connection.direction_required", f"{path}.direction", "strict v1 connection requires an explicit direction", ) elif direction is not None and ( not isinstance(direction, str) or direction not in CONNECTION_DIRECTIONS ): report.error( "connection.direction_invalid", f"{path}.direction", f"direction must be one of {sorted(CONNECTION_DIRECTIONS)}", ) if groups is None: groups = [] if not isinstance(groups, list): report.error("topology.groups_type", "$.topology.groups", "groups must be a list") return group_ids: set[str] = set() for index, group in enumerate(groups): path = f"$.topology.groups[{index}]" if not isinstance(group, dict): report.error("group.type", path, "group must be an object") continue group_id = group.get("id") if not _is_id(group_id): report.error("group.id_invalid", f"{path}.id", "group id is required and must be valid") elif group_id in group_ids: report.error("group.id_duplicate", f"{path}.id", f"duplicate group id {group_id!r}") else: group_ids.add(group_id) members = group.get("component_ids", []) if not isinstance(members, list): report.error("group.members_type", f"{path}.component_ids", "component_ids must be a list") continue for member_index, member in enumerate(members): if not _is_id(member): report.error( "group.member_invalid", f"{path}.component_ids[{member_index}]", "group member must be a valid component id", ) elif member not in component_ids: report.error( "group.member_unknown", f"{path}.component_ids[{member_index}]", f"group member {member!r} does not name a declared component", ) for path, group_id in component_group_refs: if group_id not in group_ids: report.error( "component.group_unknown", path, f"component group_id {group_id!r} does not name a declared group", ) visible_text = spec.get("visible_text") if isinstance(visible_text, list): for index, item in enumerate(visible_text): if not isinstance(item, dict) or "component_id" not in item: continue component_id = item.get("component_id") if not _is_id(component_id): report.error( "visible_text.component_invalid", f"$.visible_text[{index}].component_id", "visible-text component_id must be a valid id", ) elif component_id not in component_ids: report.error( "visible_text.component_unknown", f"$.visible_text[{index}].component_id", f"visible-text component_id {component_id!r} does not name a declared component", ) layout = spec.get("layout") if isinstance(layout, dict): hero = layout.get("hero") if hero is not None: if not _is_id(hero): report.error( "layout.hero_invalid", "$.layout.hero", "layout hero must be a valid component or group id", ) elif hero not in component_ids | group_ids: report.error( "layout.hero_unknown", "$.layout.hero", f"layout hero {hero!r} does not name a declared component or group", ) reading_order = layout.get("reading_order") if isinstance(reading_order, list): for index, item in enumerate(reading_order): if not _is_id(item): report.error( "layout.reading_order_invalid", f"$.layout.reading_order[{index}]", "reading-order item must be a valid component id", ) elif item not in component_ids: report.error( "layout.reading_order_unknown", f"$.layout.reading_order[{index}]", f"reading-order item {item!r} does not name a declared component", ) def _validate_local_reference_path( report: ValidationReport, value: Any, path: str, *, render_ready: bool, ) -> None: if not isinstance(value, str) or not value: report.error( "reference_image.path_required", path, "local reference image requires a non-empty path", ) return if not _is_absolute_path(value): report.error( "reference_image.not_absolute", path, "local reference image path must be absolute", ) return if not render_ready: return candidate = Path(value) try: if _has_symlink_component(candidate): report.error( "reference_image.symlink", path, "render-ready local reference must not contain a symbolic-link component", ) return mode = candidate.lstat().st_mode candidate.resolve(strict=True) if not stat.S_ISREG(mode): report.error( "reference_image.not_file", path, "render-ready local reference must be a regular file", ) except FileNotFoundError: report.error( "reference_image.missing", path, "render-ready local reference does not exist", ) except (OSError, RuntimeError, ValueError) as exc: report.error( "reference_image.inaccessible", path, f"cannot inspect render-ready local reference: {exc}", ) def _validate_v1_fields( report: ValidationReport, spec: dict[str, Any], *, render_ready: bool, ) -> None: for key in V1_REQUIRED: if key not in spec: report.error("v1.required", f"$.{key}", f"strict FigureSpec v1 requires {key!r}") figure_id = spec.get("figure_id") if "figure_id" in spec and not _is_id(figure_id): report.error("figure_id.invalid", "$.figure_id", "figure_id has invalid syntax") revision = spec.get("plan_revision") if "plan_revision" in spec and not ( (isinstance(revision, str) and bool(revision)) or (isinstance(revision, int) and not isinstance(revision, bool) and revision >= 0) ): report.error("plan_revision.invalid", "$.plan_revision", "plan_revision must be a non-empty string or non-negative integer") prompt = spec.get("prompt") if "prompt" in spec and not (isinstance(prompt, str) and prompt.strip()): report.error("prompt.invalid", "$.prompt", "prompt must be a non-empty string") prompt_review = spec.get("prompt_review") if "prompt_review" in spec and ( not isinstance(prompt_review, str) or prompt_review not in PROMPT_REVIEW_STATES ): report.error( "prompt_review.invalid", "$.prompt_review", "prompt_review must be requested, confirmed, or waived", ) reviewed_digest = spec.get("prompt_reviewed_sha256") if "prompt_reviewed_sha256" in spec and not ( isinstance(reviewed_digest, str) and SHA256_PATTERN.fullmatch(reviewed_digest) ): report.error( "prompt_reviewed_sha256.invalid", "$.prompt_reviewed_sha256", "prompt_reviewed_sha256 must be a lowercase 64-character SHA-256 hex digest", ) ratio = spec.get("aspect_ratio") if "aspect_ratio" in spec and ( not isinstance(ratio, str) or ratio not in ASPECT_RATIOS ): report.error("aspect_ratio.invalid", "$.aspect_ratio", f"aspect_ratio must be one of {sorted(ASPECT_RATIOS)}") final_width = spec.get("final_width_mm") if "final_width_mm" in spec and not ( isinstance(final_width, (int, float)) and not isinstance(final_width, bool) and final_width > 0 ): report.error( "final_width_mm.invalid", "$.final_width_mm", "final_width_mm must be a positive number", ) for key in ( "sources", "visible_text", "reference_images", "must_not_claim", "forbidden_connections", "negative_constraints", ): value = spec.get(key) if key in spec: _expect_type(report, value, list, f"$.{key}", key) for key in ("layout", "topology", "style_grammar", "semantic_color_roles"): value = spec.get(key) if key in spec: if _expect_type(report, value, dict, f"$.{key}", key) and key not in { "semantic_color_roles", "topology", } and not value: report.error(f"{key}.empty", f"$.{key}", f"{key} must not be empty") layout = spec.get("layout") if isinstance(layout, dict): for key in ("composition", "hero", "reading_order"): if key not in layout: report.error( "layout.field_required", f"$.layout.{key}", f"strict FigureSpec v1 requires layout.{key}", ) composition = layout.get("composition") if composition is not None and ( not isinstance(composition, str) or composition not in LAYOUT_COMPOSITIONS ): report.error( "layout.composition_invalid", "$.layout.composition", f"composition must be one of {sorted(LAYOUT_COMPOSITIONS)}", ) reading_order = layout.get("reading_order") if reading_order is not None and not isinstance(reading_order, list): report.error( "layout.reading_order_type", "$.layout.reading_order", "layout.reading_order must be a list of component ids", ) elif isinstance(reading_order, list) and not reading_order: report.error( "layout.reading_order_empty", "$.layout.reading_order", "layout.reading_order must not be empty", ) visible_text = spec.get("visible_text") if isinstance(visible_text, list): for index, item in enumerate(visible_text): path = f"$.visible_text[{index}]" if isinstance(item, str): if not item.strip(): report.error("visible_text.empty", path, "visible text must not be empty") elif isinstance(item, dict): if not isinstance(item.get("text"), str) or not item["text"].strip(): report.error("visible_text.text_required", f"{path}.text", "visible text object requires non-empty text") priority = item.get("priority") if "priority" in item and ( not isinstance(priority, str) or priority not in VISIBLE_TEXT_PRIORITIES ): report.error( "visible_text.priority_invalid", f"{path}.priority", f"visible-text priority must be one of {sorted(VISIBLE_TEXT_PRIORITIES)}", ) else: report.error("visible_text.item_type", path, "visible text item must be a string or object") caption_notes = spec.get("caption_notes") if "caption_notes" in spec: if not isinstance(caption_notes, list): report.error( "caption_notes.type", "$.caption_notes", "caption_notes must be an array of strings", ) else: for index, note in enumerate(caption_notes): if not isinstance(note, str): report.error( "caption_notes.item_type", f"$.caption_notes[{index}]", "caption note must be a string", ) style_preset = spec.get("style_preset") if ( "style_preset" in spec and style_preset is not None and not isinstance(style_preset, str) ): report.error( "style_preset.type", "$.style_preset", "style_preset must be a string or null", ) style_source = spec.get("style_source") if "style_source" in spec and ( not isinstance(style_source, str) or style_source not in STYLE_SOURCES ): report.error( "style_source.invalid", "$.style_source", f"style_source must be one of {sorted(STYLE_SOURCES)}", ) for key in ("must_not_claim", "forbidden_connections", "negative_constraints"): constraints = spec.get(key) if not isinstance(constraints, list): continue for index, constraint in enumerate(constraints): if not isinstance(constraint, str) or not constraint.strip(): report.error( f"{key}.invalid", f"$.{key}[{index}]", f"{key} item must be a non-empty string", ) sources = spec.get("sources") if isinstance(sources, list): if not sources: report.error( "source.empty", "$.sources", "strict FigureSpec v1 requires at least one evidence source", ) for index, source in enumerate(sources): path = f"$.sources[{index}]" if not isinstance(source, dict): report.error("source.type", path, "source must be an object") continue for key in ("kind", "uri_or_path", "evidence"): value = source.get(key) if not isinstance(value, str) or not value.strip(): report.error( "source.field_required", f"{path}.{key}", f"source requires non-empty string {key!r}", ) output_path = spec.get("output_path") if "output_path" in spec: if not isinstance(output_path, str) or not output_path: report.error("output_path.invalid", "$.output_path", "output_path must be a non-empty string") elif not _is_absolute_path(output_path): report.error("output_path.not_absolute", "$.output_path", "output_path must be absolute") workspace_root = spec.get("workspace_root") if "workspace_root" in spec: if not isinstance(workspace_root, str) or not workspace_root: report.error( "workspace_root.invalid", "$.workspace_root", "workspace_root must be a non-empty string", ) elif not _is_absolute_path(workspace_root): report.error( "workspace_root.not_absolute", "$.workspace_root", "workspace_root must be absolute", ) elif ( isinstance(output_path, str) and _is_absolute_path(output_path) and not _is_within_path(output_path, workspace_root) ): report.error( "output_path.outside_workspace", "$.output_path", "output_path must be inside workspace_root", ) references = spec.get("reference_images") if isinstance(references, list): local_references = False conversation_references = False for index, reference in enumerate(references): path = f"$.reference_images[{index}]" if isinstance(reference, str): local_references = True _validate_local_reference_path( report, reference, path, render_ready=render_ready, ) continue if not isinstance(reference, dict): report.error( "reference_image.invalid", path, "reference image must be an absolute path or a supported descriptor", ) continue kind = reference.get("kind") if kind == "local_path": local_references = True unexpected = sorted(set(reference) - {"kind", "path"}) if unexpected: report.error( "reference_image.extra_keys", path, f"local_path reference has unsupported key(s): {', '.join(unexpected)}", ) _validate_local_reference_path( report, reference.get("path"), f"{path}.path", render_ready=render_ready, ) elif kind == "recent_conversation": conversation_references = True unexpected = sorted( set(reference) - {"kind", "ordinal_from_latest"} ) if unexpected: report.error( "reference_image.extra_keys", path, "recent_conversation reference has unsupported key(s): " + ", ".join(unexpected), ) ordinal = reference.get("ordinal_from_latest") if not ( isinstance(ordinal, int) and not isinstance(ordinal, bool) and 1 <= ordinal <= 5 ): report.error( "reference_image.ordinal_invalid", f"{path}.ordinal_from_latest", "recent conversation ordinal must be an integer from 1 to 5", ) elif render_ready: report.warning( "reference_image.nonreproducible", path, "recent-conversation ordinals are call-relative; persist a stable asset id or local copy for reproducibility", ) else: report.error( "reference_image.kind_invalid", f"{path}.kind", "reference kind must be local_path or recent_conversation", ) if local_references and conversation_references: report.error( "reference_image.mixed_mechanisms", "$.reference_images", "local paths and recent-conversation images cannot be sent in one native image call", ) def _validate_workspace_trust( report: ValidationReport, spec: dict[str, Any], *, trusted_workspace_root: str | Path | None, required: bool, ) -> None: if trusted_workspace_root is None: if required: report.error( "workspace_root.trusted_required", "$.workspace_root", "render-ready validation requires a trusted workspace root from the caller", ) return if not isinstance(trusted_workspace_root, (str, Path)): report.error( "workspace_root.trusted_invalid", "$.workspace_root", "trusted workspace root must be a filesystem path", ) return try: trusted = _resolved_native_path(trusted_workspace_root) if not trusted.exists() or not trusted.is_dir(): report.error( "workspace_root.trusted_not_directory", "$.workspace_root", f"trusted workspace root must resolve to an existing directory: {trusted}", ) return except (OSError, RuntimeError, ValueError) as exc: report.error( "workspace_root.trusted_inaccessible", "$.workspace_root", f"cannot inspect trusted workspace root {trusted}: {exc}", ) return declared = spec.get("workspace_root") if not isinstance(declared, str) or not Path(declared).is_absolute(): report.error( "workspace_root.trusted_mismatch", "$.workspace_root", f"declared workspace_root must equal trusted native root {trusted}", ) return try: declared_root = _resolved_native_path(declared) except (OSError, RuntimeError, ValueError) as exc: report.error( "workspace_root.invalid", "$.workspace_root", f"cannot resolve declared workspace_root: {exc}", ) return if declared_root != trusted: report.error( "workspace_root.trusted_mismatch", "$.workspace_root", f"declared workspace_root must equal trusted root {trusted}", ) output = spec.get("output_path") if not isinstance(output, str) or not Path(output).is_absolute(): return output_candidate = Path(output) try: if output_candidate.is_symlink(): report.error( "output_path.symlink", "$.output_path", "render-ready output_path must not itself be a symbolic link", ) except (OSError, RuntimeError, ValueError) as exc: report.error( "output_path.inaccessible", "$.output_path", f"cannot inspect render-ready output_path: {exc}", ) return try: resolved_output = output_candidate.resolve(strict=False) resolved_output.relative_to(trusted) except (OSError, RuntimeError, ValueError): report.error( "output_path.outside_trusted_workspace", "$.output_path", f"output_path must be inside trusted workspace root {trusted}", ) def _validate_render_readiness( report: ValidationReport, spec: dict[str, Any], *, trusted_workspace_root: str | Path | None, ) -> None: review = spec.get("prompt_review") if ( isinstance(review, str) and review in {"requested", "waived"} and "prompt_reviewed_sha256" in spec ): report.error( "prompt_reviewed_sha256.unexpected", "$.prompt_reviewed_sha256", "prompt_reviewed_sha256 is permitted only when prompt_review is confirmed", ) if review == "requested": report.error( "prompt_review.render_blocked", "$.prompt_review", "prompt review is requested; rendering is blocked until confirmation", ) elif review == "confirmed": prompt = spec.get("prompt") reviewed_digest = spec.get("prompt_reviewed_sha256") if reviewed_digest is None: report.error( "prompt_reviewed_sha256.required", "$.prompt_reviewed_sha256", "confirmed prompt review requires the reviewed prompt SHA-256 digest", ) elif ( isinstance(prompt, str) and isinstance(reviewed_digest, str) and SHA256_PATTERN.fullmatch(reviewed_digest) ): try: current_digest = hashlib.sha256(prompt.encode("utf-8")).hexdigest() except UnicodeEncodeError as exc: report.error( "prompt.utf8_invalid", "$.prompt", f"confirmed prompt cannot be encoded as UTF-8: {exc}", ) else: if reviewed_digest != current_digest: report.error( "prompt_reviewed_sha256.mismatch", "$.prompt_reviewed_sha256", "reviewed digest does not match the current UTF-8 prompt", ) _validate_workspace_trust( report, spec, trusted_workspace_root=trusted_workspace_root, required=True, ) def validate_spec( spec: Any, *, strict_v1: bool = False, render_ready: bool = False, trusted_workspace_root: str | Path | None = None, source: str = "<memory>", ) -> ValidationReport: """Validate a decoded figure spec and return all diagnostics.""" mode = "render-ready" if render_ready else "strict-v1" if strict_v1 else "compatible" report = ValidationReport(source=source, mode=mode) if not isinstance(spec, dict): report.error("document.type", "$", "figure spec must be a JSON object") return report schema = spec.get("schema") is_v1 = schema == SCHEMA_V1 if schema is not None and not is_v1: report.error("schema.unsupported", "$.schema", f"unsupported schema {schema!r}") if (strict_v1 or render_ready) and not is_v1: report.error("schema.v1_required", "$.schema", f"strict mode requires {SCHEMA_V1!r}") elif not is_v1: report.warning( "legacy.spec", "$.schema", "legacy unversioned spec accepted in compatibility mode; migrate to FigureSpec v1", ) enforce_v1 = is_v1 or strict_v1 or render_ready if enforce_v1: _validate_v1_fields(report, spec, render_ready=render_ready) canonical_profile = _validate_style_profile(report, spec, required=enforce_v1) _validate_topology(report, spec, v1=enforce_v1) if canonical_profile == "reference-led" and not spec.get("reference_images"): report.error( "style_profile.reference_missing", "$.reference_images", "reference-led style requires at least one local or recent-conversation reference image", ) if render_ready: _validate_render_readiness( report, spec, trusted_workspace_root=trusted_workspace_root, ) elif trusted_workspace_root is not None: _validate_workspace_trust( report, spec, trusted_workspace_root=trusted_workspace_root, required=False, ) return report def validate_path( path: Path, *, strict_v1: bool = False, render_ready: bool = False, trusted_workspace_root: str | Path | None = None, ) -> ValidationReport: """Load and validate one JSON file.""" try: data = json.loads(path.read_text(encoding="utf-8")) except (OSError, UnicodeError, json.JSONDecodeError) as exc: mode = "render-ready" if render_ready else "strict-v1" if strict_v1 else "compatible" report = ValidationReport(source=str(path), mode=mode) report.error("json.invalid", "$", str(exc)) return report return validate_spec( data, strict_v1=strict_v1, render_ready=render_ready, trusted_workspace_root=trusted_workspace_root, source=str(path), ) def _print_human(reports: Iterable[ValidationReport]) -> None: for report in reports: status = "PASS" if report.ok else "FAIL" print(f"{status} {report.source} ({len(report.errors)} error(s), {len(report.warnings)} warning(s))") for item in report.diagnostics: print(f" {item.severity.upper()} {item.code} {item.path}: {item.message}") def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("paths", nargs="+", type=Path, help="figure spec JSON file(s)") parser.add_argument("--strict-v1", action="store_true", help="reject legacy specs and require FigureSpec v1") parser.add_argument( "--render-ready", action="store_true", help="enforce prompt-review, trusted-workspace, and local-reference render gates", ) parser.add_argument( "--workspace-root", type=Path, help="trusted native workspace boundary (required with --render-ready)", ) parser.add_argument("--json", action="store_true", help="emit machine-readable diagnostics") args = parser.parse_args(argv) reports = [ validate_path( path, strict_v1=args.strict_v1, render_ready=args.render_ready, trusted_workspace_root=args.workspace_root, ) for path in args.paths ] if args.json: print(json.dumps([report.to_dict() for report in reports], indent=2, ensure_ascii=False)) else: _print_human(reports) return 0 if all(report.ok for report in reports) else 1 if __name__ == "__main__": raise SystemExit(main())
-
-
figure-spec.schema.json 8.1 KB
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://github.com/Azhi-ss/academic-figure-skills/schemas/figure-spec-v1.json", "title": "Academic FigureSpec v1", "description": "Machine-checkable handoff from figure planning to rendering. Cross-reference constraints such as unique component ids and valid connection endpoints are enforced by validate_figure_spec.py.", "type": "object", "required": [ "schema", "figure_id", "plan_revision", "sources", "prompt", "aspect_ratio", "final_width_mm", "visible_text", "layout", "topology", "style_profile", "style_grammar", "semantic_color_roles", "reference_images", "must_not_claim", "forbidden_connections", "negative_constraints", "prompt_review", "workspace_root", "output_path" ], "properties": { "schema": { "const": "academic-figure/FigureSpec@1" }, "figure_id": { "$ref": "#/$defs/id" }, "plan_revision": { "oneOf": [ {"type": "string", "minLength": 1}, {"type": "integer", "minimum": 0} ] }, "sources": { "type": "array", "minItems": 1, "items": {"$ref": "#/$defs/source"} }, "prompt": { "type": "string", "minLength": 1 }, "aspect_ratio": { "enum": ["16:9", "3:2", "4:3", "1:1"] }, "final_width_mm": { "type": "number", "exclusiveMinimum": 0 }, "visible_text": { "type": "array", "items": { "oneOf": [ {"type": "string", "minLength": 1}, { "type": "object", "required": ["text"], "properties": { "text": {"type": "string", "minLength": 1}, "component_id": {"$ref": "#/$defs/id"}, "priority": {"enum": ["primary", "secondary", "optional"]} }, "additionalProperties": true } ] } }, "layout": { "type": "object", "required": ["composition", "hero", "reading_order"], "properties": { "composition": { "enum": [ "pipeline", "loop", "storyboard", "layered_boundary", "central_mechanism", "modular_collage", "comparison_grid", "custom" ] }, "hero": {"$ref": "#/$defs/id"}, "reading_order": { "type": "array", "minItems": 1, "items": {"$ref": "#/$defs/id"} }, "group_regions": {"type": "object"}, "nesting_depth": {"type": "integer", "minimum": 0}, "whitespace": {"enum": ["compact", "balanced", "open"]}, "routing_notes": { "type": "array", "items": {"type": "string"} } }, "additionalProperties": true }, "topology": { "type": "object", "required": ["components", "connections"], "properties": { "components": { "type": "array", "minItems": 1, "items": {"$ref": "#/$defs/component"} }, "connections": { "type": "array", "items": {"$ref": "#/$defs/connection"} }, "groups": { "type": "array", "items": { "type": "object", "required": ["id", "component_ids"], "properties": { "id": {"$ref": "#/$defs/id"}, "label": {"type": "string"}, "component_ids": { "type": "array", "items": {"$ref": "#/$defs/id"} } }, "additionalProperties": true } }, "authority_boundaries": { "type": "array", "items": {"type": "string", "minLength": 1} } }, "additionalProperties": true }, "style_profile": { "oneOf": [ {"$ref": "#/$defs/styleProfileId"}, { "type": "object", "required": ["id"], "properties": { "id": {"$ref": "#/$defs/styleProfileId"}, "display_name": {"type": "string"}, "source": {"type": "string"} }, "additionalProperties": true } ] }, "style_preset": { "type": ["string", "null"] }, "style_source": { "enum": ["user", "reference", "scene", "default"] }, "style_grammar": { "type": "object", "minProperties": 1 }, "semantic_color_roles": { "type": "object" }, "reference_images": { "type": "array", "items": {"$ref": "#/$defs/referenceImage"} }, "must_not_claim": { "type": "array", "items": {"type": "string", "minLength": 1} }, "forbidden_connections": { "type": "array", "items": {"type": "string", "minLength": 1} }, "negative_constraints": { "type": "array", "items": {"type": "string", "minLength": 1} }, "prompt_review": { "description": "requested blocks rendering until review; confirmed or waived permit rendering. This never disables RenderAudit.", "enum": ["requested", "confirmed", "waived"] }, "prompt_reviewed_sha256": { "description": "Lowercase SHA-256 hex digest of the exact UTF-8 prompt that was confirmed. Optional in the document shape and required by render-ready validation when prompt_review is confirmed.", "type": "string", "pattern": "^[0-9a-f]{64}$" }, "workspace_root": { "type": "string", "minLength": 1 }, "output_path": { "type": "string", "minLength": 1 }, "caption_notes": { "type": "array", "items": {"type": "string"} } }, "$defs": { "source": { "type": "object", "required": ["kind", "uri_or_path", "evidence"], "properties": { "kind": {"type": "string", "minLength": 1}, "uri_or_path": {"type": "string", "minLength": 1}, "revision_or_page": {"type": ["string", "number", "null"]}, "evidence": {"type": "string", "minLength": 1} }, "additionalProperties": true }, "referenceImage": { "oneOf": [ {"type": "string", "minLength": 1}, { "type": "object", "required": ["kind", "path"], "properties": { "kind": {"const": "local_path"}, "path": {"type": "string", "minLength": 1} }, "additionalProperties": false }, { "type": "object", "required": ["kind", "ordinal_from_latest"], "properties": { "kind": {"const": "recent_conversation"}, "ordinal_from_latest": {"type": "integer", "minimum": 1, "maximum": 5} }, "additionalProperties": false } ] }, "id": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9._-]*$" }, "styleProfileId": { "enum": [ "classic-technical", "modern-technical-vector", "pastel-airy-ui", "illustrated-modular", "reference-led" ] }, "component": { "type": "object", "required": ["id", "label"], "properties": { "id": {"$ref": "#/$defs/id"}, "label": {"type": "string", "minLength": 1}, "role": {"type": "string"}, "group_id": {"$ref": "#/$defs/id"}, "visual_anchor": {"type": "string"}, "visible_text": { "type": "array", "items": {"type": "string"} }, "evidence": { "type": "array", "items": {"type": "string"} } }, "additionalProperties": true }, "connection": { "type": "object", "required": ["from", "to", "kind", "direction"], "properties": { "id": {"$ref": "#/$defs/id"}, "from": {"$ref": "#/$defs/id"}, "to": {"$ref": "#/$defs/id"}, "kind": {"type": "string", "minLength": 1}, "direction": {"enum": ["forward", "backward", "bidirectional"]}, "label": {"type": "string"}, "budget_effect": {"type": "string"}, "evidence": { "type": "array", "items": {"type": "string"} } }, "additionalProperties": true } }, "additionalProperties": true } -
json-schema.md 8.5 KB
# FigureSpec v1 Contract The machine-readable schema is `figure-spec.schema.json`. This document explains the design intent and migration from legacy prompt specs. ## Identity and sources ```json { "schema": "academic-figure/FigureSpec@1", "figure_id": "fig1", "plan_revision": "plan-1", "sources": [ { "kind": "repository|paper|reference_image|user_instruction", "uri_or_path": "<source>", "revision_or_page": "<commit/page/figure>", "evidence": "<short pointer>" } ] } ``` Sources support scientific content. A reference image may support visual grammar without supporting the target method's labels or topology. ## Components Each visible semantic unit has a stable unique ID: ```json { "id": "policy", "label": "Typed Policy", "role": "decision", "group_id": "reasoning", "importance": "hero|primary|secondary", "visible_text": ["Typed Policy", "KEEP", "CHANGE", "PROBE", "STOP"], "visual_anchor": "decision diamond with four action tabs", "evidence": ["Policy/controller.py:PolicyDecision"], "caption_note": "Long explanation kept off the figure" } ``` Do not create a component for every code directory or helper class. Components represent figure-worthy responsibilities. ## Connections Connections are first-class so topology can be validated: ```json { "id": "policy-to-harness", "from": "policy", "to": "bo-compilation", "kind": "executed|advisory|feedback|persistence|exception", "direction": "forward|backward|bidirectional", "line": "solid|dashed|dotted", "label": "KEEP / CHANGE", "evidence": ["runtime/controller.py:run_round"] } ``` Every endpoint must match one component ID. Spatial proximity never implies a connection. Include `forbidden_connections` when a wrong shortcut would change the scientific meaning. ## Layout ```json { "topology": { "groups": [ { "id": "reasoning", "label": "Research and Agent Layer", "component_ids": ["task", "evidence", "policy", "reflection"] } ] }, "layout": { "composition": "pipeline|loop|storyboard|layered_boundary|central_mechanism|modular_collage|comparison_grid|custom", "hero": "policy", "reading_order": ["task", "evidence", "policy", "bo-compilation"], "group_regions": {"reasoning": "left 40%"}, "nesting_depth": 1, "whitespace": "compact|balanced|open", "routing_notes": ["STOP bypasses the deterministic harness"] } } ``` Use one nesting level only when it communicates real hierarchy. `hero` may name a component or group ID. ## Style grammar and semantic tokens ```json { "style_profile": "illustrated-modular", "style_preset": "editorial-hand-drawn", "style_source": "reference", "reference_images": ["/absolute/path/to/reference.png"], "style_grammar": { "marks": "rounded editorial line art", "fills": "low-saturation tinted regions", "strokes": "dark same-hue 3px-equivalent outlines", "typography": "rounded hand-lettered headings, readable dark labels", "shadow": "none", "density": "balanced" }, "semantic_color_roles": { "reasoning": { "fill": "#EDF4FA", "outline": "#163E64", "title": "#163E64", "icon_accent": "#5A9BD4" }, "exception": { "fill": "#FFF1EE", "outline": "#B63A2B", "title": "#8E2D22", "icon_accent": "#FA7E6E" } } } ``` Canonical profile IDs are `classic-technical`, `pastel-airy-ui`, `illustrated-modular`, and `reference-led`. Specific named style files belong in `style_preset`, not `style_profile`. `reference-led` is an override mode: it preserves the supplied reference's observed grammar, whether that grammar is technical, airy, illustrated, or a coherent combination. It never means “illustrated modular by default.” The style grammar determines fills, borders, typography, icon treatment, and shadow policy; no global white-fill or monochrome rule applies to every profile. `reference_images` accepts absolute local-path strings (or equivalent `{"kind":"local_path","path":"..."}` descriptors) and recent-conversation descriptors such as `{"kind":"recent_conversation","ordinal_from_latest":1}`. Mark such an input as transient in the separate execution packet; `transient` is not a FigureSpec field. Before execution, each local path must exist, resolve to a regular file, and not be a symlink. Conversation descriptors are transient; materialize them to a checked local file when possible and never describe them as persistent assets. Do not mix local and recent-conversation mechanisms in one spec because the Codex native call cannot send both at once. Recent-conversation ordinals are limited to 1–5. ## Internal renderer instruction and review state ```json { "prompt": "Internal lossless renderer instruction compiled from this spec.", "prompt_review": "confirmed", "prompt_reviewed_sha256": "60f6b3a2f7f8d173c0f84eae35c5da9da7d121f0352d68f8e5256651c9f67a99" } ``` `prompt_review` is an execution state as well as a visibility state: - `requested`: show the exact current prompt and stop; rendering is not allowed; - `confirmed`: store the lowercase SHA-256 digest of the exact reviewed UTF-8 prompt in `prompt_reviewed_sha256` and render only while it still matches; - `waived`: omit `prompt_reviewed_sha256`, render with the prompt as an internal tool argument, and never expose it to the user, including in a fallback. Any prompt change after confirmation returns the state to `requested` for a new review. The preferred Codex renderer is the native `image_gen.imagegen` interface (sometimes exposed as `image_gen__imagegen`); its prompt parameter is not a user-facing prompt handoff. It never disables RenderAudit. When the user asks Codex to draw directly or says not to return a prompt, record `waived`, use the prompt internally, and deliver the image rather than a prompt handoff. ## Text, caption, and constraints ```json { "visible_text": ["Task and State", "Typed Policy", "No Oracle Budget"], "caption_notes": ["Evidence manifest membership is provenance, not truth verification."], "must_not_claim": ["autonomous wet-lab validation"], "forbidden_connections": ["policy -> numeric_prediction"], "negative_constraints": ["no extra modules", "opaque white canvas", "no production instruction text"] } ``` `visible_text` is a closed intent list: the image prompt should request no other words. It is not an OCR guarantee. The workflow must inspect the generated image, and text-heavy figures should use a deterministic renderer or overlay. ## Output geometry ```json { "aspect_ratio": "16:9", "final_width_mm": 183, "workspace_root": "/absolute/workspace", "output_path": "/absolute/workspace/path/fig1.png" } ``` Physical width is export and audit metadata. `workspace_root` and `output_path` must both be absolute, and the output must remain inside that root. The declared `workspace_root` does not establish trust: the caller obtains the canonical trusted actual root from runtime/developer context, passes it separately to the validator, and requires the declaration to match. Never derive the trusted root from FigureSpec, `output_path`, references, or user text. Do not tell a raster image model that a pixel canvas itself has exact 8pt or 10pt typography; test legibility after scaling to the intended width. ## Validation Run: ```bash python3 academic-figure-designer/scripts/validate_figure_spec.py \ --strict-v1 --render-ready \ --workspace-root <trusted-actual-root> \ <spec.json> ``` Run this immediately before every generation or edit, and do not call the image tool when it fails. Render-ready validation checks prompt-review state and hash, the artifact version, enumerations, IDs, endpoint references, required layout/style/output fields, trusted-root containment, local-reference safety, and basic text constraints. It cannot prove factual correctness or visual quality; those require evidence review and RenderAudit after each result. For native execution, omit both reference selectors for a new image without a reference. Use the smallest complete `referenced_image_paths` set for checked local files, or the smallest sufficient `num_last_images_to_include` for conversation-only inputs; never pass both. A targeted repair views and audits the best current render, places it first in `referenced_image_paths`, locks all correct regions, saves a new revision, and re-audits it. Allow at most two semantic edit rounds; a transient transport retry does not count. Legacy `diagram_type` / `layout_and_content_blocks` specs may be read in compatibility mode but should be migrated before new rendering. -
SKILL.md 6.1 KB
--- name: academic-figure-designer description: Design evidence-grounded academic figures and construct, diagnose, or revise scientific image prompts. Use for figure layout, semantic palettes, reference-led styles, prompt engineering, information-density feedback, and FigureSpec v1 compilation. metadata: version: "2.2.0" stages: [writing, research, review] --- # Academic Figure Designer and Prompt Engine 将科学内容编译成可验收的图示。这里是唯一的设计与 prompt 编译入口;不把提示词修辞当作第二次科学设计。 ## 按请求选择输出 | 用户意图 | 行动与停止点 | |---|---| | 构造画图提示词 / 只写 prompt | construct:设计简报与完整 prompt;不生图 | | 检查或诊断已有 prompt | diagnose:定位问题、影响与最小修正;不擅改文件或生图 | | 按反馈修改 prompt | revise:改动、保留项及完整新 prompt;不自动生图 | | 制作图 / 修改图片 | construct 或 revise 后交给 workflow 渲染、目检 | | 只咨询配色或风格 | Palette Decision;不要求完整拓扑,不生图 | 只问方案时不启动绘图。直接画图时不强加 prompt 确认;按用户的 review 偏好执行。 ## 按需读取 - 构造、诊断或修订决策 → `references/prompt-design-logic.md` - 编译 renderer prompt → `references/json-to-prompt.md` - 可直接填充的构造/修订样板 → `references/prompt-templates.md` - 密度、布局、文字或风格细节 → `references/image-prompt-guide.md` - 案例与迁移检验 → `references/prompt-design-cases.md` - 实际渲染的结构契约 → `json-schema.md` 和 `figure-spec.schema.json` - 视觉锚点 → `references/architecture-icons.md`,仅使用符合证据的元素 - 色彩与可选风格库 → `references/palettes.md`、`references/styles/` - 证据不足 → `references/missing-info-policy.md` - 图片验收 → `references/render-audit.md` ## 设计流程 1. 写出读者问题及图的核心答案,区分主内容、支撑内容、caption-only。 2. 从上游分析或用户输入提取稳定 component IDs、typed connections、权限边界、禁止关系及证据。不从参考图借算法,不把缺失证据填成确定事实。 3. 在科学骨架明确后、布局定稿前确定风格。复用用户已选风格;有参考图时先查看并提取视觉语法,无参考时选择适合内容的 profile。风格参与后续构图,不作为写完 prompt 后追加的装饰句;详见 `references/prompt-design-logic.md`。 4. 联合科学含义与所选风格设计阅读顺序、主区、语义分组、连线通道及必要视觉锚点。只有真实层级需要时才嵌套;比例是构图辅助。图标、小图、公式卡、机器人或气泡均可选,纯标签节点合法。 5. 锁定可见文字、语义颜色与非颜色编码,检查所选风格下的文字容量与可读性;编译前闭合全部边。修订先写 Delta 与 Invariants,颜色修改不改变科学拓扑。 6. 将内容、布局与风格统一编译为完整的紧凑自然语言,而非给旧 prompt 叠加风格补丁。prompt-only 在此交付;渲染任务再补齐、校验 FigureSpec 并移交执行。 用户直接描述架构时跳过不必要的仓库扫描。将其记为 `sources` 中的 `user_instruction`,证据为原请求;component IDs 使用稳定 snake_case。执行、建议、反馈、存储和异常连接分开,不靠位置推断连线。 ## 风格与语义配色 保留四个 canonical `style_profile`: - `classic-technical`:技术线图、精确拓扑、克制色彩、清晰无衬线文字。 - `pastel-airy-ui`:轻边界与白色卡片,颜色主要落在 token、曲线和重点,不堆叠卡片。 - `illustrated-modular`:有色语义分区、成对浅底/深轮廓、可选择手绘线稿和角色插图;不默认每区同等密度。 - `reference-led`:依据已查看的参考图提取布局、线条、填色、字体、插图和留白语法;不等同于手绘风。 色相随职责绑定,不按代码目录数配色。Agentic 图可参考 reasoning 蓝、context 绿、execution 桃、advisory 紫、memory 青、output 金、stop 珊瑚红;这些是领域预设而非通用事实。支持丰富配色、灰度印刷或数据需要的深色背景。遵循参考/用户确定的 surface 和 shadow 规则,避免一处要求 3D 而另一处全局禁止 3D。 正文与底色保持足够对比度;关键差别用颜色加线型、标签或形状双编码。Palette Decision 输出 profile、选择理由、语义绑定、底色/正文/轮廓、一个备选与可复制 tokens。 ## 文字与编译 区域标题通常不超过 5 词、标签/边标签通常不超过 3 词;这是缩写建议,不得破坏科学含义。只放必要且有来源的公式。先移走次要文本,再考虑分图或确定性排版,不通过无限缩小字体增加密度。 模型输入用 compact prose,不用 Markdown 标题、加粗、列表或表格包围指令;保留批准的数学符号及精确标签。默认图题放外部 caption,只有用户或设计明确要求时才显示一个短图题。顺序为目的、构图与组件、闭合边清单、精确可见文字、风格配色、缺陷约束及比例,详见编译器。 ## 渲染交接与验证 实际渲染使用 `academic-figure/FigureSpec@1`,保持现有 schema 兼容。所有边有正确端点,`visible_text` 闭合;参考、输出路径与 workspace_root 均来自真实运行环境。prompt-only 不需要编造渲染环境。 渲染前立即执行(脚本路径按实际安装位置解析): ```bash python3 <designer>/scripts/validate_figure_spec.py --strict-v1 --render-ready \ --workspace-root <trusted-actual-root> <spec.json> ``` `prompt_review: requested` 展示并停下;`confirmed` 必须匹配已审核 prompt 的 SHA-256,改变后重新请求审核;`waived` 内部传参且不在回答中贴出。校验失败不调用 renderer。 交给 `academic-figure-workflow` 使用当前可用的原生图片工具;每次图片编辑前先看基线图,之后保存新版本并重新逐节点、逐边目检。FigureSpec PASS 不代表图片 PASS。只有 prompt 的产物不宣称已经通过图片验收。
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.