cardbuddy 0.14.3 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +0 -0
- package/dist/preview-editor/assets/index-BkbBxDTT.css +1 -0
- package/dist/preview-editor/assets/index-Bro07DTa.js +313 -0
- package/dist/preview-editor/index.html +2 -2
- package/dist/standalone.js +3 -0
- package/dist/vendored/card-editor/runtime/adapter.js +2 -2
- package/dist/vendored/mcp/client.mjs +9 -2
- package/dist/vendored/server/core/ai-chat.js +1702 -134
- package/dist/vendored/server/core/browser.js +12 -3
- package/dist/vendored/server/core/cardFiles.js +3 -0
- package/dist/vendored/server/core/cardHistory.js +1 -0
- package/dist/vendored/server/core/cardImportMeta.js +7 -6
- package/dist/vendored/server/core/cardOpenFolder.js +1 -0
- package/dist/vendored/server/core/cardSave.js +1 -0
- package/dist/vendored/server/core/cardSync.js +3 -0
- package/dist/vendored/server/core/cardValidate.js +16 -5
- package/dist/vendored/server/core/codeBridge.js +5 -1
- package/dist/vendored/server/core/logStream.js +1 -0
- package/dist/vendored/server/core/sliceStatic.js +24 -4
- package/dist/vendored/server/core/sliceUpload.js +1 -0
- package/dist/vendored/server/core/turnJournal.js +6 -0
- package/dist/vendored/skills/card-skill-trainer/SKILL.md +257 -201
- package/dist/vendored/skills/card-skill-trainer/scripts/diagnose_case.mjs +14 -82
- package/dist/vendored/skills/card-skill-trainer/scripts/lib/diagnosis.mjs +207 -0
- package/dist/vendored/skills/card-skill-trainer/scripts/lib/layout-correction-sim.mjs +62 -0
- package/dist/vendored/skills/card-skill-trainer/scripts/lib/paradigm-router.mjs +76 -0
- package/dist/vendored/skills/card-skill-trainer/scripts/lib/pixel-worker-runner.mjs +31 -0
- package/dist/vendored/skills/card-skill-trainer/scripts/lib/pixel-worker.mjs +138 -0
- package/dist/vendored/skills/card-skill-trainer/scripts/lib/scoring.mjs +24 -20
- package/dist/vendored/skills/card-skill-trainer/scripts/lib/telemetry.mjs +46 -0
- package/dist/vendored/skills/card-skill-trainer/scripts/plan_next_round.mjs +4 -1
- package/dist/vendored/skills/card-skill-trainer/scripts/run_round.mjs +279 -90
- package/dist/vendored/skills/card-skill-trainer/scripts/score_round.mjs +74 -2
- package/dist/vendored/skills/card-skill-trainer/scripts/sink_rules.mjs +127 -0
- package/dist/vendored/skills/dsl-card-ai/SKILL.md +1 -1
- package/dist/vendored/skills/dsl-card-generator/SKILL.md +208 -380
- package/dist/vendored/skills/dsl-card-generator/references/dsl_structure.md +1 -15
- package/dist/vendored/skills/dsl-card-generator/references/expression_engine.md +11 -20
- package/dist/vendored/skills/dsl-card-generator/references/generation_pitfalls.md +233 -61
- package/dist/vendored/skills/dsl-card-generator/references/ir-format.md +202 -4
- package/dist/vendored/skills/dsl-card-generator/references/iteration_protocol.md +87 -0
- package/dist/vendored/skills/dsl-card-generator/references/previewer_contract.md +1 -1
- package/dist/vendored/skills/dsl-card-generator/references/quickref.md +42 -33
- package/dist/vendored/skills/dsl-card-generator/references/recipe_snippets/title-underline-overlay.json +59 -11
- package/dist/vendored/skills/dsl-card-generator/references/recipes.md +44 -8
- package/dist/vendored/skills/dsl-card-generator/references/rules.md +26 -6
- package/dist/vendored/skills/dsl-card-generator/references/scripts_reference.md +54 -0
- package/dist/vendored/skills/dsl-card-generator/references/semantic_adjudication.md +23 -0
- package/dist/vendored/skills/dsl-card-generator/references/slices_convention.md +6 -6
- package/dist/vendored/skills/dsl-card-generator/references/spec_to_schema_patterns.md +33 -4
- package/dist/vendored/skills/dsl-card-generator/references/ui_fidelity_rules.md +13 -1
- package/dist/vendored/skills/dsl-card-generator/scripts/add_component.mjs +5 -14
- package/dist/vendored/skills/dsl-card-generator/scripts/autofix_schema.py +133 -2
- package/dist/vendored/skills/dsl-card-generator/scripts/check_fidelity.mjs +226 -19
- package/dist/vendored/skills/dsl-card-generator/scripts/check_magic_values.mjs +6 -1
- package/dist/vendored/skills/dsl-card-generator/scripts/check_topology.py +0 -35
- package/dist/vendored/skills/dsl-card-generator/scripts/crop_slices.mjs +92 -6
- package/dist/vendored/skills/dsl-card-generator/scripts/expand_ir.mjs +277 -27
- package/dist/vendored/skills/dsl-card-generator/scripts/gate.mjs +147 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/generate_cards.mjs +12 -8
- package/dist/vendored/skills/dsl-card-generator/scripts/ir_merge.mjs +288 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/ir_restore.mjs +175 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/iterate.mjs +1015 -54
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/component_contract.mjs +315 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/geometry_audit.mjs +131 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/layout-tokens.mjs +1 -1
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/layout_rules.mjs +160 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/paths.mjs +23 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/paths.py +0 -37
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/python.mjs +99 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/rules/adaptive-width.mjs +105 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/rules/bindings.mjs +260 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/rules/expr.mjs +52 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/rules/image.mjs +96 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/rules/registry.mjs +166 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/rules/structure.mjs +127 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/rules/walk.mjs +61 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/scope_alias.mjs +125 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/slicePath.mjs +17 -5
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/slice_dedupe.mjs +102 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/v3_assemble.mjs +5727 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/v3_extract.mjs +4214 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/v3_shared.mjs +1110 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lint_card.mjs +322 -71
- package/dist/vendored/skills/dsl-card-generator/scripts/preflight.mjs +87 -43
- package/dist/vendored/skills/dsl-card-generator/scripts/readiness.mjs +634 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/register_card_template.mjs +5 -8
- package/dist/vendored/skills/dsl-card-generator/scripts/render_card.mjs +91 -43
- package/dist/vendored/skills/dsl-card-generator/scripts/route_input.mjs +7 -11
- package/dist/vendored/skills/dsl-card-generator/scripts/spec_audit.mjs +272 -46
- package/dist/vendored/skills/dsl-card-generator/scripts/spec_to_schema_v3.mjs +43 -10499
- package/dist/vendored/skills/dsl-card-generator/scripts/v3_regression.mjs +188 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/validate_schema.py +23 -15
- package/dist/vendored/skills/shared/exit-codes.md +79 -0
- package/dist/vendored/skills/shared/spec-contract.md +118 -0
- package/dist/vendored/skills/sketch-spec-to-card/SKILL.md +43 -20
- package/dist/vendored/skills/sketch-spec-to-card/references/spec-schema.md +4 -4
- package/dist/vendored/skills/sketch-spec-to-card/scripts/build_prompt.py +47 -9
- package/dist/vendored/skills/sketch-spec-to-card/scripts/cluster_states.py +14 -25
- package/dist/vendored/skills/sketch-spec-to-card/scripts/parse_meaxure.py +546 -91
- package/dist/vendored/skills/sketch-spec-to-card/scripts/png_utils.py +51 -5
- package/dist/vendored/skills/sketch-spec-to-card/scripts/test_text_only_artboard.py +217 -0
- package/dist/vendored/skills/sketch-spec-to-card/scripts/vision.py +64 -34
- package/package.json +1 -1
- package/dist/preview-editor/assets/index-Cm0USikc.js +0 -307
- package/dist/preview-editor/assets/index-cbTCHp8J.css +0 -1
- package/dist/vendored/skills/card-skill-trainer/scripts/test_missing_slice.py +0 -122
- package/dist/vendored/skills/dsl-card-generator/scripts/analyze_component_usage.mjs +0 -153
|
@@ -1,191 +1,116 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: dsl-card-generator
|
|
3
|
-
description:
|
|
3
|
+
description: 生成、编辑 FinMall/YNet 低代码卡片 schema.json + data.json(15 个可渲染组件、$ 表达式绑定、v-show、globalSet、alertCard、Canvas 自绘)。适用:从图片/设计稿/MeaXure 导出生成卡片、编辑已有卡片、逆向解释 schema。触发词:图片生成卡片、读图建卡、编辑卡片、改卡片。核心流程:route_input 判输入形态 →(MeaXure 导出先经 sketch-spec-to-card 前处理)→ 整树 IR 一次下发建卡 → validate+lint 双门禁 → iterate 视觉闭环(改卡用 add_component/ir_patch)。常规任务只读 references/quickref.md,避免加载全部 references。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# DSL 卡片 Schema 生成器(DSL Card Schema Generator)
|
|
7
7
|
|
|
8
8
|
为 FinMall/YNet 卡片设计器生成合规的 schema.json + data.json。本 skill 把平台当作一套**带版本号的 JSON DSL**:卡片 = 数据字典 + 组件树 + 属性元数据 + 样式分组 + 指令 + 插槽 + 事件动作。一切结构都有据可查,不臆造。
|
|
9
9
|
|
|
10
|
-
> **图片/AI 生成卡片 = 你(Agent)直接读图产出 schema
|
|
11
|
-
|
|
12
|
-
> **自包含 /
|
|
13
|
-
|
|
14
|
-
## 0.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
4. **类型+值成对检查**:`borderRadius` 必须配 `borderRadiusType`、`border` 必须配 `isBorder`、`shadow` 必须配 `isShadow`——只写值不写类型开关 = 渲染器静默丢弃(pitfalls §R44,lint `r44-*` 拦截,expand_ir 自动补)。
|
|
33
|
-
6. **卡片背景不透明**5. **卡片背景不透明**:卡片背景**不存在透明**——Root/首层容器必须有 `background.backgroundColor` + `backgroundType:"01"`;取色优先读标注 `cardFill`,标注缺失从聚焦截图中心采样兜底(pitfalls §R43,lint `r43-card-transparent-background` 拦截)。
|
|
34
|
-
8. **`rect.width:"100%"` 必须可压缩**:100% 宽节点保持 `flexShrink:"1"`(默认值),**禁止同节点显式 `flexShrink:"0"`**,否则固定宽同级节点会被挤出父容器/溢出。与关键 Text 的 `flexShrink:"0"` 按 `width` 分流(auto→R17,100%→R22)。**受外宽约束的多子容器(width 非 auto 且 2+ 并列子节点)至少一个子节点 flexShrink:1**(R35)——全部 shrink:0 会导致外容器宽度变化时定宽累加溢出;`width:auto` 内容自适应容器内的固定子元素可保持 shrink:0。详见 `rules.md §九` / `generation_pitfalls.md §9-R22/R35`。
|
|
35
|
-
|
|
36
|
-
9. **Text 高度与 maxLine 必须协调**:`maxLine=0`(允许换行)时**不设 rect.height**(固定高度 + 换行 = scrollHeight > clientHeight → 文本溢出裁切);`maxLine=1`(单行)时保留 spec rect.height 防止意外撑高。判定:spec 文本高度 > fontSize × 1.5 → 多行(maxLine=0 无高度),否则 → 单行(maxLine=1 有高度)。详见 `references/ui_fidelity_rules.md §1`。
|
|
37
|
-
10. **标注 + 图像交叉验证(模型多模态能力)**:生成卡片时必须**同时读取 spec.json 标注和 card-N.png 聚焦截图**——标注提供精确数值(坐标/字号/颜色),图像提供视觉真相(相对位置/留白/层级关系)。两者冲突时标注优先但标记缺陷;标注缺失时从图像推断(如垂直居中推算 Tab 高度 = 文字高度 + 上下间距 × 2)。详见 `references/ui_fidelity_rules.md §8`。
|
|
38
|
-
11. **透明度禁止表达式(铁律 R57)**:移动端渲染不支持 `style.other.opacity` 走表达式(`itemValueFrom:"1"`),预览构建产物更是完全不消费组件级 opacity(截图查不出来)。透明度需随状态变化时走**固定范式**:按用到的透明度取值生成等量**静态变体节点**,统一套一层 Row/Column 容器——**容器宽高 = 被展示节点宽高 + `other.overflow:"hidden"`**,**点击等事件挂在容器上**,变体用**互斥 v-show** 显隐切换实现视觉透明度变化。lint `r57-opacity-expression` ERROR;机械改写 `scripts/apply_opacity_pattern.mjs --id <卡id>`。详见 `recipes.md §17` / `recipe_snippets/opacity-switch.json`(serviceEvaluation 为首个落地卡)。
|
|
39
|
-
12. **非 UI 变更不做视觉验证(铁律)**:视觉验证(`render_card.mjs` / `card_screenshot` / Playwright 截图)只在变更会改变画面时做。改 `inputParams` / 绑定表达式取值逻辑 / `eventactions` 事件代码 / `data.json` / 文档脚本 → 只跑 validate + lint + `derive_data_json --check`,再用**单元断言**收口(`evalExpr` 比对表达式返回值;`new Function(code).call(假 this)` 跑 customAction 断言 `state`,`code` 与 `compiled` 两份都要跑)。改 `style.*` / 节点增删移动 / 静态文案 / 图片资源 / v-show 条件 → 才做视觉收口。边界:改动副作用会改变布局几何(文案变长换行、`width:"100%"` 内容变长、v-show 改变可见节点集合)时仍按 UI 变更处理。详见 `references/rules.md §七.1`。
|
|
40
|
-
13. **画板聚焦(多画板必须先选卡,铁律 §十三)**:设计稿含多个画板而用户未指定目标时——**UI 产物允许全量生成**(sketch-spec-to-card 管线一次跑完全部画板),但**卡片生成必须以单个画板 / 单个 UI 产物为单位**:先用 `spec_tree.mjs --list-cards <UI目录>`(按「画板序号.卡片序号」展开每个画板下的卡片)或 `parse_meaxure.py --src <导出目录> --list` / `UI/<稿名>/manifest.json`(`canvases[]`)/ `clusters.json`(`cards[]`)机械取全量画板,按 **`画板序号.卡片序号` 编号列出(序号 1 起;一个画板含 N 张卡则展开为 K.1 ~ K.N,详见 §13.4)+ 末尾追加一项 `全部`**;**让用户选的方式 = 正文里逐条写出清单 + 一句明确提问,然后停止输出、等用户回序号再继续**——编辑器助手面板**没有**弹选项工具(不存在 `request_user_input`,**不要去调用或寻找它**),更不要替用户挑;宿主若自带同名工具才可优先弹选项,但那不是前提,不要依赖。**UI 产物允许回 `全部` 全量生成**(sketch-spec-to-card 管线整份导出全跑);**卡片生成默认以单个画板 / 单个 cardKey 为单位**,用户回 `全部` 才视为显式批量授权(交付说明产了几张卡)。**禁止**自行挑画板、**禁止**未经同意批量产卡、**禁止**「先建一张看看」。系统级弹窗不可实现,「正文列清单 + 兜底 `1..n + 全部` → 停下等序号」即等价物;清单**逐行配图**(每画板行下紧跟它自己的预览图绝对路径,缺图显式标缺失,禁止堆末尾),转给用户时逐条内联 Markdown 图片看图选。详见 `references/rules.md §十三`。
|
|
41
|
-
14. **数字语义变量提取(中文+数字混排串铁律 §十四)**:每个落盘文本先过 **AI 语义解析**——串里含**运行期数字信息**(金额含千分号 / 笔数 / 利率 / 期限 / 日期等,判定看「数字是否随数据变化」而非「是否含数字」;版本号 / 固定营销话术不提取)时,关键数字抽成 `inputParams` 变量(金额 `type:"number"` + **原始数字** defaultValue),原混排串用**表达式拼接**展示(`'静态文案' + <数字表达式> + '静态文案'`,`itemValueFrom:"1"` + `itemDefaultValue` 兜底);**格式化后带千分号的金额照惯例 = 原始数字变量 + `amount_formatting.md` §3 格式化表达式**(中文前后缀拼在表达式外)。**禁止**整串写死、整串绑一个 string 变量、把格式化串写进字典、正则见数字就拆。lint `r61-text-numeric-literal` 提醒级复核。详见 `references/rules.md §十四`。
|
|
42
|
-
15. **图表绘制层序(铁律 R62)**:Canvas 即时模式后画压先画 → **出码顺序必须 = 底 → 顶**:**坐标系/参考系线条(柱状图网格线与轴线、折线图网格与刻度线、雷达图环与辐射线、环形底环/轨道)最底层 → 数据标记(柱/折线/多边形/扇区/高亮弧)→ 文字标签(轴标签/值标签/中心分数)最上层**。**禁止**「先填充后画网格」反范式;spec 元素顺序不可照抄(标注导出常把网格线排在数据图元之后)。数据标记半透明(spec `opacity<1`)把透明度**乘进颜色/渐变 stop**(代理 ctx 无 `globalAlpha`),底层参考线才透得出来。生成器 `chartBarCanvasCode` 已用 `chartPaintLayers` 强制分层,护栏 `tools/tests/chart-layer-order.test.mjs`。详见 `references/rules.md §十五` / `recipes.md §15/§18`。
|
|
10
|
+
> **图片/AI 生成卡片 = 你(Agent)直接读图产出 schema,不接外部接口**:读截图/设计稿(多模态),按组件/样式/表达式/事件规则直接写出合规 schema.json + data.json,再用内置校验器自查。详见 §8 Workflow A 与 references/image_to_card.md。
|
|
11
|
+
|
|
12
|
+
> **自包含 / 可移植**:离线渲染用 `vendor/preview/` 构建产物(宿主 `npm run build:skill-preview` 产出)+ 系统 Chrome(CDP),只依赖 Node 内置模块(>=22)。卡片/切图目录默认取 cwd,可用 `DSL_CARD_PROJECT_ROOT` / `DSL_CARD_CARDS_DIR` / `DSL_CARD_SLICES_DIR` / `DSL_CARD_META_DIR` / `DSL_CARD_PREVIEW_DIR` / `DSL_CARD_BASELINES_DIR` 覆盖(单一来源 `scripts/lib/paths.mjs`)。
|
|
13
|
+
|
|
14
|
+
## 0. 铁律索引(最高纪律;完整定义 / 根因 / 验收见 `references/rules.md`)
|
|
15
|
+
|
|
16
|
+
1. **视觉优先** — 模型视觉判断 > 脚本启发式,冲突以视觉为准(rules.md §七 / ui_fidelity_rules.md §8)
|
|
17
|
+
2. **绝不臆造** — 组件/属性/事件/action 须 export/meta/renderer-proven(rules.md §一)
|
|
18
|
+
3. **不污染 DSL** — 禁写 `$schema`/`x-*`/Generator 产物;整体替换后跑 `diff_card.mjs`(rules.md §二)
|
|
19
|
+
4. **根节点不设样式宽度** — 宽度由 `view.width` 承载,style 不放 rect 组(rules.md §九)
|
|
20
|
+
5. **标注可信度分层** — 属性值读标注禁抄存量卡;几何看实图/容器边界;间距用 margin;卡底取 `cardFill`(rules.md §十一 / pitfalls §9-R1/R8-R10)
|
|
21
|
+
6. **渲染器默认样式显式覆盖 + 运行期数据必绑定** — Row/Column/ListLayout 默认 padding:2px/gap:4px/居中须归零;金额/日期等绑 inputParams(rules.md §九 / amount_formatting.md)
|
|
22
|
+
7. **类型+值成对** — borderRadius↔borderRadiusType、border↔isBorder、shadow↔isShadow,只写值不写开关 = 静默丢弃(R44,lint `r44-*`)
|
|
23
|
+
8. **卡片背景不可完全透明** — Root/首层须有背景声明;半透明合法(R43,pitfalls §R43)
|
|
24
|
+
9. **width:"100%" 必须可压缩** — 保持 `flexShrink:"1"`,禁同节点 shrink:0(R22/R35,rules.md §九)
|
|
25
|
+
10. **Text 高度与 maxLine 协调** — maxLine=0 不设 rect.height;spec 文本高 > fontSize×1.5 判多行(ui_fidelity_rules.md §1)
|
|
26
|
+
11. **透明度禁表达式(R57)** — 走静态变体 + 等宽高 `overflow:hidden` 容器 + 事件上移 + 互斥 v-show(recipes.md §17)
|
|
27
|
+
12. **非 UI 变更不做视觉验证** — 改 inputParams/表达式/事件/data 只跑 validate+lint+derive+单元断言(rules.md §七.1)
|
|
28
|
+
13. **画板聚焦(多画板必须先选卡)** — 未指定时机械列清单(`spec_tree.mjs --list-cards` / `parse_meaxure.py --list` / manifest `canvases[]`,`画板序号.卡片序号` + 末尾 `全部`)+ 停等序号,禁自挑/未授权批量/「先建一张看看」(rules.md §十三)
|
|
29
|
+
14. **数字语义变量提取** — 含运行期数字(金额/笔数/利率/期限/日期)抽 inputParams + 表达式拼接;禁整串写死/绑 string/正则见数字就拆(R61,rules.md §十四)
|
|
30
|
+
15. **图表绘制层序(R62)** — 底→顶:参考线/网格/轨道最底 → 数据标记 → 文字标签最顶;禁先填充后画网格(rules.md §十五)。机械兜底在 v3 生成器 `chartPaintLayers`(`lib/v3_shared.mjs`)+ 回归测试 `tools/tests/chart-layer-order.test.mjs`;**lint 不拦这一条**(无法可靠解析 Canvas 表达式的调用顺序),AI 手写时靠渲染后目视。
|
|
31
|
+
16. **宽度自适应(占满禁写死 px,R66)** — 顶层 `view.width` = 卡面宽(非画板宽);纵向流父级里占满父内容盒的容器**禁写 px 宽**,用 `100%` 或不写(meta 默认即 100%),px 只给真固定元素(ir-format.md §2f,lint `r66-fullwidth-px`)。写死 px 的卡在非设计宽度的宿主容器里锁死不自适应。
|
|
43
32
|
|
|
44
33
|
## 0.5 速查优先
|
|
45
34
|
|
|
46
|
-
常规任务只看 `references/quickref.md
|
|
35
|
+
常规任务只看 `references/quickref.md`(最常用组件骨架、表达式、事件范式、命令、片段索引);quickref 未覆盖才按需读其他 references。详见 `rules.md §五`。
|
|
47
36
|
|
|
48
37
|
## 1. 平台模型速览
|
|
49
38
|
|
|
50
|
-
-
|
|
51
|
-
- **渲染器**(vendor/preview/):schema.json → buildPreview() → 预览树 → RenderTree.vue 递归渲染。实现 **15** 个组件类(见下表);编辑器 palette 注册 **20** 个,多出的 6 个(CheckGroup/RadioButton/ProgressSlider/Video/Map/MultiColumn)**预览不渲染**,仅在有平台导出证明其 JSON 形状时才生成。
|
|
39
|
+
- **渲染器**(vendor/preview/):schema.json → buildPreview() → RenderTree.vue 递归渲染。实现 **15** 个组件类;编辑器 palette 注册 20 个,多出 6 类(CheckGroup/RadioButton/ProgressSlider/Video/Map/MultiColumn)**预览不渲染**,仅在有平台导出证明 JSON 形状时才生成。
|
|
52
40
|
- **数据流**:dictionary.inputParams[] 是数据模型;$key 绑定引用字典字段;ListLayout/GridLayout 作用域插槽内 $field 引用当前项;表达式经 evalExpr 在 with(vars) 下求值。
|
|
53
|
-
- **事件**:eventactions[] 里 customAction 跑 JS,this 持有 state/data/setData/setRootData/addEventListener/postMessage;JSAPI
|
|
41
|
+
- **事件**:eventactions[] 里 customAction 跑 JS,this 持有 state/data/setData/setRootData/addEventListener/postMessage;JSAPI 平台注入全局 `ynet`,**直接 `ynet.callJSAPI(...)`**(禁 window. 前缀与存在性守卫,铁律 R56)。
|
|
54
42
|
|
|
55
43
|
## 2. 顶层结构 & data.json
|
|
56
44
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
- data.json 必须**逐字节**等于 { inputParams[i].key: inputParams[i].defaultValue }。增删改字段时同步改 data.json,或跑 scripts/derive_data_json.py --overwrite。
|
|
62
|
-
- view 是根组件树(className:"Root"),用 components(非 slots)。其余组件用 slots[].components。
|
|
45
|
+
- 顶层:version("1.0.0")、pageId、name、desc、platform("002")、dictionary.inputParams[]、view。
|
|
46
|
+
- inputParams[] 每项完整 7 字段 `{ key, name, type, defaultValue, desc, rule, children }`(rule 空=`{type:'',options:{}}`,children 空=`[]`;type ∈ boolean|string|number|object|array)。expand_ir 自动补全;validate 缺失 → ERROR(pitfalls §R49)。
|
|
47
|
+
- data.json **逐字节**等于 `{ inputParams[i].key: defaultValue }`;改字段同步改 data.json 或跑 `derive_data_json.py --overwrite`。
|
|
48
|
+
- view 是根组件树(className:"Root",用 components 非 slots);其余组件用 slots[].components。
|
|
63
49
|
|
|
64
50
|
## 3. 组件速查(15 个可渲染)
|
|
65
51
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
- **本地预览可访问**:自包含 `vendor/vite.config.mjs` 与 `scripts/render_card.mjs` 把 `/slices/*` 映射到宿主 `src/slices/*`,离线截图可直接加载卡片切图,无需先同步远端;宿主若另有 dev server(如 cardbuddy:8787)也只需挂载同款 `/slices/*` 静态中间件。
|
|
90
|
-
- **导出目录切图(`99.切图/*`)不渲染**:MeaXure 导出会在图层里塞入 `99.切图/...` 组(导出清单/占位,非卡片内容),几乎每张卡都有。渲染阶段(`buildLeaf`、`imageFromSlice`)跳过图层名以 `99.切图` 开头的 slice,避免凭空注入切换语音/箭头等图标并误引用(曾导致 `切换语音@3x.png` 被 200+ 次错误引用)。过滤只看图层名前缀,不看导出路径。
|
|
91
|
-
- 元素名 ↔ 导出文件名靠 `lib/slicePath.mjs` 的 `resolveSliceExport` 归一化(去 `@Nx` / 尾随 `_icon` / 扩展名后按 basename 匹配)对齐;匹配不到的 slice 退化占位图。
|
|
92
|
-
- 完整机制、目录对照、匹配规则、常见错误与校验清单见 `references/slices_convention.md`。
|
|
93
|
-
- **MultiText**:叶,click。属性 textList → itemList[] → 每段 properties(value/color/fontSize/fontWeight/fontStyle/textDecoration/backgroundColor/tag)。一行多段不同字体文本;点击 event.__do__ 冒泡去重。
|
|
94
|
-
- **Divider**:叶,无事件。默认 rect=100%x1, bg=#f1f1f1。纯样式分割/间距。
|
|
95
|
-
- **ViewContainer**:叶,action。属性 customClass、customProps(可 $绑定)、customRemarkImg。默认 rect=100%/height=auto。宿主自定义组件占位,预览画占位块。
|
|
96
|
-
|
|
97
|
-
> 编辑器专属(预览不渲染):MultiColumn/CheckGroup/RadioButton/ProgressSlider/Video/Map。仅在有平台导出时生成,否则预览画"未知组件"占位但仍渲染子树。
|
|
52
|
+
完整 JSON 骨架 + 属性 itemId 表见 `references/component_specs.md`。**编辑器专属 6 类预览不渲染**:MultiColumn/CheckGroup/RadioButton/ProgressSlider/Video/Map(仅平台导出时生成,否则占位但渲染子树)。
|
|
53
|
+
|
|
54
|
+
| 组件 | 事件 | 关键属性/默认 | 用途 |
|
|
55
|
+
|---|---|---|---|
|
|
56
|
+
| Root | onReady | 宽由 `view.width="375"` 承载;style 不放 rect 组 | 根容器(components) |
|
|
57
|
+
| Row | click | 默认 width:100%、gap:4、居中、padding:2 | 横向布局/可点击区 |
|
|
58
|
+
| Column | click | 同 Row;flexDirection:column、justifyContent:center | 纵向堆叠 |
|
|
59
|
+
| ListLayout | click | slotScope:true;value(数组绑定)/direction/row-spacing/edge-insets | 数组逐项重复模板 |
|
|
60
|
+
| GridLayout | click | slotScope:true;value/column/row-spacing/item-spacing | 等分列网格 |
|
|
61
|
+
| AbsoluteLayout | — | align(9 方位);子元素绝对定位 | 叠加/角标 |
|
|
62
|
+
| Canvas | onMeasured | event.canvas 设计稿坐标系;onMeasured 自绘 | 自定义绘制 |
|
|
63
|
+
| Text | click | value(经 doI18n);无默认样式 | 文本 |
|
|
64
|
+
| MultiText | click | itemList[] 多段 value/color/fontSize/fontWeight | 一行多段富文本 |
|
|
65
|
+
| Button | click | value/disabled(**"false" 也为真**);默认 #0079f2 120x40 r100 | 按钮 |
|
|
66
|
+
| Input | events:[] | value($key 回写 rt.state)/placeholder/inputType/maxLength;实时值读 `this.data.<key>` | 输入 |
|
|
67
|
+
| Icon | click | icon(glyph)/color/content;默认 32x32;**必须 emits:click** 否则双触发 | 图标 |
|
|
68
|
+
| Image | click | value(@filestore/$绑定);cropMode 00 铺满/01 填充 | 图片 |
|
|
69
|
+
| Divider | — | 默认 100%x1 #f1f1f1 | 分割/间距 |
|
|
70
|
+
| ViewContainer | action | customClass/customProps($绑定) | 宿主自定义组件占位 |
|
|
71
|
+
|
|
72
|
+
### 切图资产唯一落点(issue-slices 系列,强制)
|
|
73
|
+
|
|
74
|
+
**全集见 `references/slices_convention.md`**。要点:① 唯一落点 `src/slices/` 扁平(`/`→`_`),schema 引用 `/slices/<扁平名>`(远端由 syncRemote 改写 @filestore);② 文件名禁 URL 保留字符 `# ? % & +`——静默 404(网络 200 零报错),重命名不转义(禁 `%23`),lint r31b/r31c;③ 语义化命名(`iconArrowRight@3x.png` 式)全项目同名唯一,改名成套做(`rewriteSliceRefs`);④ 落地即判重(sha256+像素容差,lint r60)、仅引用才拷贝(expand_ir/generate_cards 自动汇聚)、上传按内容判重只传一次;⑤ 导出目录 `99.切图/*` 不渲染;元素名↔导出文件名靠 `lib/slicePath.mjs → resolveSliceExport` 归一化。
|
|
98
75
|
|
|
99
76
|
## 4. 表达式与数据绑定(核心引擎)
|
|
100
77
|
|
|
101
78
|
完整规则见 references/expression_engine.md。要点:
|
|
102
79
|
|
|
103
|
-
- **$
|
|
104
|
-
- **itemValueFrom**:"0"
|
|
105
|
-
- **作用域插槽**:
|
|
106
|
-
-
|
|
107
|
-
- **
|
|
108
|
-
- **
|
|
109
|
-
- **Input 双向回写**:Input 的 value 绑定形如 $key 时,渲染层兜底:onInput 写 `rt.state[key]`(**只写运行期克隆 rt.state、绝不写 rt.rootScope**,故打字不触发"保存到本地"脏标记)。实时输入值在事件代码里仅用 `this.data.payAmount` 读(this.data 的唯一合法用途),无需"交互前 flush";普通运行态变量一律用 `this.state` 读(lint `r51` 拦截误用)。Input 无可绑定事件(events:[]),卡片无法自己接线 change,故由渲染层兜底。
|
|
80
|
+
- **$ 表达式**:itemValueFrom:"1" 的 itemValue 是 JS 表达式,作用域变量改名 $foo 注入 `with(vars)` 求值;未定义 $ 变量解析为 undefined(不抛错),`$foo || 默认值` 兜底可生效;逐项 try/catch,单项失败保持 meta 默认值。
|
|
81
|
+
- **itemValueFrom**:"0"常量 / "1"表达式(**必须**带 itemDefaultValue)/ "2"图片值。
|
|
82
|
+
- **作用域插槽**:slotScope 下**表达式**用 `$fieldName` 直读 item 字段(禁 `$$.field`,lint R50);`$$` 仅指整个 item。**事件脚本无 `$$`**:item 字段已展开到 `this.state` 直接读(铁律,lint R55 ERROR)。
|
|
83
|
+
- **itemCondition**:属性级条件显隐 `a.b` / `a.!b` / `a.b|c`;Properties 空数组 = 沿用 meta 默认。
|
|
84
|
+
- **v-show**:directives[] itemKey:"v-show",showType 00 始终显/01 条件显/02 条件隐 + condition.expression;**condition.name 必填**(<15 字符与表达式一致,>=15 起短名);**容器类组件(MultiColumn/List/Grid/Absolute/Canvas/Map/Video/ViewContainer)必须外套 Row/Column 设在包裹层**(lint r53 ERROR)。
|
|
85
|
+
- **Input 回写**:value 绑 `$key` 时 onInput 写 rt.state[key](只写克隆不脏 rootScope);实时输入值事件代码**仅 `this.data.<key>`**(唯一合法用途),其余一律 this.state(lint r51)。
|
|
110
86
|
|
|
111
87
|
## 5. 样式系统
|
|
112
88
|
|
|
113
|
-
|
|
89
|
+
**itemId 权威来源 = `vendor/preview/meta/style-meta.json`**(完整表见 dsl_structure.md / component_specs.md)。分组:100 flex(flexDirection=**006**、justifyContent、alignItems、gap、flexShrink)|200 rect|300 background(backgroundType 00 透明|01 颜色|02 图片|03 渐变 + Color/Gradient)|400 padding / 500 margin(xType ""|0|1 + 值 + 四边分项)|600 borderRadius(borderRadiusType 成对)|700 border(isBorder)|800 shadow(isShadow)|900 transform|1000 other(overflow、**opacity 只允许静态常量 0-100**,禁表达式——铁律 R57)|1100 font(color/fontSize/lineHeight/textAlign/**fontWeight 枚举 400|500|600**/isMaxLine/maxLine)|1200 image(cropMode)|1300 position。
|
|
114
90
|
|
|
115
|
-
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
- 400 padding:paddingType(""无|0 全边|1 自定义)、padding、paddingLeft/Top/Right/Bottom。
|
|
119
|
-
- 500 margin:marginType(""无|0 全边|1 自定义)、margin、marginLeft/Top/Right/Bottom。
|
|
120
|
-
|
|
121
|
-
> **渲染器默认样式(必读)**:Row/Column/ListLayout 未显式设置时默认注入 `padding:2px` + `gap:4px` + `justify-content:center`(Column 内容垂直居中),ListLayout 默认 `edge-insets {2,2,2,2}`。**`expand_ir.mjs` 的 `ensureCoreDefaults()` 会自动为每个节点补入核心样式默认值**(margin=0、background=透明、padding=0[仅容器]、borderRadius=0、gap=0[仅容器]),消除隐性默认值的不确定性(pitfalls §R48)。但仍需显式设置 Column justifyContent flex-start、ListLayout edge-insets '{0,0,0,0}' 等 expand_ir 不覆盖的属性(见 §9-R11)。
|
|
122
|
-
|
|
123
|
-
> **间距语义(必读)**:元素与相邻元素的间距用 `margin`(marginTop/Bottom),**不用 padding**——padding 表达"盒子内部留白",会污染 box 高(fidelity Δh 误报、下一元素位置计算偏差);padding 只用于结构性内边距(容器/卡片内边距、文本缩进 paddingLeft)。**卡片圆角放最外层 Root**(圆角与背景均读 spec 标注),内层白底主体不放圆角(被外层白底填平)。详见 `generation_pitfalls.md §9-R8/R9`。
|
|
124
|
-
- 600 borderRadius:borderRadiusType(""无|0 全角|1 自定义)、borderRadius、各角。
|
|
125
|
-
- 700 border:isBorder(0|1)、borderWidth、borderStyle(solid|dashed|dotted)、borderColor。
|
|
126
|
-
- 800 shadow:isShadow、shadowColor、shadowX/Y/Blur/Spread。
|
|
127
|
-
- 900 transform:rotate(deg)。
|
|
128
|
-
- 1000 other:overflow(hidden|visible)、opacity。**opacity 只允许静态常量(0-100)**:移动端不支持透明度表达式,预览构建产物也不消费组件级 opacity;会变化的透明度必须走透明度切换固定范式(铁律 R57,见 §0 第 11 条 / `recipes.md §17`)。
|
|
129
|
-
- 1100 font:color、fontSize、lineHeight、textAlign(left|center|right)、fontWeight(400|500|600)、fontStyle(normal)、textDecoration(none)、isMaxLine(0|1)、maxLine。
|
|
130
|
-
- 1200 image:cropMode(00 铺满|01 填充)。
|
|
131
|
-
- 1300 position:left、top、right、bottom。
|
|
132
|
-
|
|
133
|
-
解析顺序固定:rect→flex→background→padding→margin→borderRadius→border→shadow→transform→other,后覆盖前同名;boxSizing:border-box。font/image 由 Text/MultiText/Image 等单独调。颜色 rgba(r,g,b,a) 或 #rrggbb 经 adapter.doColor 归一;尺寸数字字符串经 adapter.doSize 转 px。background.backgroundType 02 图片时 backgroundImage 经 doReplaceUrl + doI18n,默认 position 50% 50%、size cover、repeat no-repeat。
|
|
134
|
-
|
|
135
|
-
> **style itemId 权威来源 = `vendor/preview/meta/style-meta.json`**,不要凭记忆。**易错**:`flexDirection` 的 itemId 是 **`006`**(不是 `002`,`002` 是 `alignItems`)。`validate_schema.py` 现已校验「样式子项 itemId 是否与该组预期一致」,写错直接 ERROR。完整避坑(含 itemValueFrom 必填、图片解析、布局陷阱、Playwright 视觉验证)见 `references/generation_pitfalls.md`。
|
|
91
|
+
> **渲染器默认样式**:Row/Column/ListLayout 默认注入 padding:2px+gap:4px+justify-content:center,ListLayout 默认 edge-insets{2,2,2,2}——必须显式归零;expand_ir ensureCoreDefaults 自动补核心默认(§R48),Column justifyContent:flex-start、ListLayout edge-insets 仍需显式(§9-R11)。
|
|
92
|
+
> **间距语义**:相邻间距用 margin 不用 padding(padding 污染 box 高);卡片圆角放最外层 Root(pitfalls §9-R8/R9)。
|
|
93
|
+
> **易错**:flexDirection 的 itemId 是 **006**(002 是 alignItems),写错 validate ERROR;解析顺序 rect→…→other 后覆盖前,boxSizing:border-box。
|
|
136
94
|
|
|
137
95
|
## 6. 事件与运行时
|
|
138
96
|
|
|
139
|
-
完整见 references/event_patterns.md +
|
|
97
|
+
完整见 references/event_patterns.md + platform_jsapi.md。要点:
|
|
140
98
|
|
|
141
|
-
- **eventactions[]
|
|
142
|
-
- **
|
|
143
|
-
- **
|
|
144
|
-
- **
|
|
145
|
-
-
|
|
146
|
-
- **slotScope item 字段在事件里直读(铁律 r55)**:slotScope:true 的 List/Grid item 事件脚本里,当前 item 的字段**直接 `this.state.<field>` 读取**(如 `var q = this.state.query;`)——这是平台保证的作用域展开,**不是**需要 `if (q === undefined && this.state.$$)` 之类兜底判断的不确定行为。事件脚本禁止出现 `$$`(含 `this.state.$$`、`$$.field`);lint `r55-event-no-dollar-dollar` ERROR 拦截。
|
|
147
|
-
- **globalSet 数据透传(铁律 r54 固定范式)**:ListLayout/GridLayout 的 item 事件里修改绑定数据禁止直接改——必须 `this.postMessage('globalSet', patch)`(patch 对象与 `setData(...)` 入参逐字一致),并**先在根节点 onReady** `this.addEventListener('globalSet', fn)` 注册监听、监听里 `self.setData(patch)` 代写;其他节点事件可直接 setData。详见 references/recipes.md §globalSet,lint `r54` 拦截。
|
|
148
|
-
- **JSAPI**(ynet.callJSAPI(name, params, cb)):**直接裸调 `ynet.callJSAPI(...)`**——ynet 是平台注入的全局,**禁止 `window.ynet` 前缀与 `typeof window !== 'undefined' && window.ynet && ...` 之类存在性守卫**(铁律,lint R56 ERROR;49 张导出卡全量裸调为证)。高频 closeAlertCard/alertCard/alertDialog/sendAiChatMessage/startRouter/showToast,低频 showLoadingEx/showPicker/showKeyboard/hideKeyboard/showDatePicker/copyToClipboard 等。回调结构 {success, error, errorMessage, data}。**完整签名 + 实测频次见 `references/platform_jsapi.md`**(权威表,不在本节重复数字)。
|
|
99
|
+
- **eventactions[]**:`{ event:{eventName,eventKey}, action:{actionType, properties:[{itemKey:"function", itemValue:{code, compiled}}]} }`。click 高频;onReady/onMeasured 就绪类生命周期首帧前跑一次,不注册被动 handler。
|
|
100
|
+
- **actionType**:customAction 跑 JS(主形态);alertCard/showToast 等是 customAction 里的 **JSAPI 调用**(不是 actionType)。
|
|
101
|
+
- **customAction 的 this**:state(运行态,写走 setData)/ data(**仅** Input 实时输入值,lint r51)/ setData(patch) / setRootData(patch,触发存盘脏标记,调试禁用) / addEventListener / postMessage。slotScope item 字段在事件里直接 `this.state.<field>` 读(铁律 r55,禁 `$$` 兜底判断)。
|
|
102
|
+
- **globalSet(铁律 r54)**:List/Grid item 事件改绑定数据必须 `this.postMessage('globalSet', patch)`(与 setData 入参一致)+ 根节点 onReady `addEventListener('globalSet')` 代写;其他节点直接 setData(recipes.md §globalSet)。
|
|
103
|
+
- **JSAPI**:裸调 `ynet.callJSAPI(name, params, cb)`(禁 window 前缀/存在性守卫,铁律 R56);回调 `{success, error, errorMessage, data}`;完整签名+频次见 platform_jsapi.md。
|
|
149
104
|
|
|
150
105
|
## 7. 通用范式(Recipes)
|
|
151
106
|
|
|
152
|
-
可复用、export-proven
|
|
153
|
-
|
|
154
|
-
| 范式 | 适用场景 | 主要来源 |
|
|
155
|
-
|---|---|---|
|
|
156
|
-
| Canvas 画布标题头 | 自绘文字标题(坐标用**设计稿 px**) | creditCardBill / dreamPlan / assetOverview |
|
|
157
|
-
| 弹一张卡片(alertCard) | 子母卡弹窗 + 回传 data | creditCardBill / monthlyBill / activityLevel |
|
|
158
|
-
| 列表展开/收起 | 长列表「查看更多」交互 | account / activityList / depositList |
|
|
159
|
-
| globalSet 子→父透传 | 子节点改根作用域 + 列表重算(**铁律 r54**:List/Grid item 改绑定数据必须走此透传,payload 即 patch、与 setData 入参一致) | serviceEvaluation(规范 patch 实现)/ activityRight / DepositHolding / creditCardBill(历史 {key,value} 实现) |
|
|
160
|
-
| 金额格式化 | 千分号 / 正负号 / 货币符 | creditCardBill($formatMoney helper) |
|
|
161
|
-
| Tab ↔ 标题头(billMode) | 多模式切换(**陷阱**:activeTab 默认值不随模式变,依赖 $activeTab 的可见性须 AND $billMode==='0') | creditCardBill |
|
|
162
|
-
| 透明度切换固定范式(R57) | 透明度随状态变化(选中/点亮/禁用):静态变体 ×N + 等宽高 overflow:hidden 容器 + 事件上移 + 互斥 v-show | serviceEvaluation(10 个表情档) |
|
|
163
|
-
|
|
164
|
-
遇到 quickref §1-§5 未覆盖的组合需求时查上表选近邻参考;复杂边界细节读 `recipes.md` 对应小节。
|
|
107
|
+
可复用、export-proven 配方全集见 **`references/recipes.md`**(Canvas 标题头 / alertCard 弹窗 / 列表展开收起 / globalSet / 金额格式化 / Tab-billMode / 手风琴 / Canvas 甜甜圈·仪表盘·雷达 / 角标 / 标题下划线 / 透明度切换等),可复制片段见 **`references/recipe_snippets/*.json`**(含 `apply` 字段;`extract_subtree.mjs` 可从导出卡抽新片段)。quickref §1-§5 未覆盖的组合需求查 recipes 选近邻。
|
|
165
108
|
|
|
166
109
|
## 7.5 意图路由(选模板零扫文件)
|
|
167
110
|
|
|
168
|
-
|
|
111
|
+
用户意图 → 脚手架意图 + 查 `references/card_index.json` 找近邻,**不扫源卡**:列表→`list`|明细→`detail`|表单→`form`|弹窗→`dialog`|多 Tab→`tab`|画布标题头→`canvas-head`|纯静态→`blank`;MeaXure 导出→Workflow 0 入口①;图片/设计稿→Workflow A。
|
|
169
112
|
|
|
170
|
-
|
|
171
|
-
|---|---|---|---|
|
|
172
|
-
| 列表 / 任务流 | `list` | 改 `$title`;ListLayout 子项模板填字段 | `tags` 含 `list` |
|
|
173
|
-
| 明细 / 详情页 | `detail` | 改 `$title`/`$detailList`/`$btnText` | `tags` 含 `detail`/`result`/`amount` |
|
|
174
|
-
| 表单 / 输入 | `form` | 加 Input + 按钮逻辑 | `tags` 含 `form` |
|
|
175
|
-
| 弹窗 / Dialog | `dialog` | 改 `$title`/`$desc`/`$confirmText`;接 alertCard | `recipes` 含 `alertCard` |
|
|
176
|
-
| 多 Tab | `tab` | 改 `$tab1`/`$tab2`/`$content` | `recipes` 含 `tab-billMode` |
|
|
177
|
-
| 画布标题头 | `canvas-head` | 改 Canvas onMeasured 绘制 | `recipes` 含 `canvas-head` |
|
|
178
|
-
| 纯静态 / 自定义 | `blank` | 用 add_component 从空容器搭起 | — |
|
|
179
|
-
| **Sketch MeaXure 标注导出建卡** | **Workflow 0 入口①** | `route_input.mjs <路径>` 判形态 → 先 `sketch-spec-to-card` 前处理出 `UI/<稿名>/` → 逐卡 Workflow A | 产物 `UI/<稿名>/clusters.json` + `card_index.json` |
|
|
180
|
-
| 图片 / 设计稿建卡 | Workflow A | 读图 + `spec_tree.mjs` → scaffold → 视觉闭环 | inventory / card_index |
|
|
181
|
-
|
|
182
|
-
> `card_index.json` 由 `build_card_index.mjs` 生成,每张卡带 `components`/`recipes`/`tags`。按 `recipes`(用过哪些范式)与 `tags`(意图)过滤即可。新增导出后先重跑该脚本。
|
|
183
|
-
>
|
|
184
|
-
> **整卡模板库**:`card_templates.json`(`build_card_templates.mjs` 生成)把存量卡按结构标签聚成 8 簇并选出代表卡。有近似存量卡时用 `scaffold_card.mjs --from <模板卡id>`(或 MCP `card_scaffold` 的 `from` 参数)整卡克隆改写——只重写 pageId/name,版式纪律与绑定范式原样继承,比空骨架堆组件快且稳;封面不复制(定稿后重新渲染)。从零建卡才走 `--intent` 空骨架。
|
|
185
|
-
>
|
|
186
|
-
> **模板沉淀闭环**:① 检索——建卡前 `resolve_card_template.mjs <一句话意图>`,命中直接 `--from` 克隆;② 沉淀——卡片交付后跑 `register_card_template.mjs --id <cardId> --check` 做新颖性检查(结构签名 Jaccard 相似度,<60% 为新模式),若是首次出现的布局/交互模式且用户确认,用 `--cluster <簇key> --keywords <通用意图词>` 登记(健康门禁:validate 0 error + lint 0 error;keywords 只用通用 UI 意图词,业务词不入库);③ 重建 `build_card_templates.mjs` 保留 pinned 代表与 keywords,人工登记永不被打分覆盖。
|
|
187
|
-
>
|
|
188
|
-
> 脚手架工具命令(scaffold_card / add_component / autofix_schema)见 §10;范式片段库(recipe_snippets/)见 §7。
|
|
113
|
+
> **整卡模板库**:有近似存量卡时 `resolve_card_template.mjs <一句话意图>` 命中即 `scaffold_card.mjs --from <模板卡id>` 整卡克隆改写(只重写 pageId/name,版式纪律原样继承)。**沉淀**:交付后 `register_card_template.mjs --id <cardId> --check` 新颖性检查(Jaccard<60% 为新模式),用户确认后登记(keywords 只用通用 UI 意图词,业务词不入库)。
|
|
189
114
|
|
|
190
115
|
## 8. 工作流
|
|
191
116
|
|
|
@@ -194,289 +119,192 @@ description: 生成、编辑并以 AI 辅助 FinMall/YNet 低代码卡片 schema
|
|
|
194
119
|
收到建卡请求,**第一步永远是机械判形态,不靠感觉**:
|
|
195
120
|
|
|
196
121
|
```bash
|
|
197
|
-
node scripts/route_input.mjs
|
|
122
|
+
node scripts/route_input.mjs <输入路径> [--json] # 只挂 MCP 无 shell 时用等价工具 card_route_input({path})
|
|
198
123
|
```
|
|
199
124
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
它给出 `kind` + 判定证据 + 下一步可直接执行的命令(含跨 skill 的上游脚本路径),四类入口:
|
|
125
|
+
四类入口(工具返回 kind + 判定证据 + 下一步命令):
|
|
203
126
|
|
|
204
|
-
1. **`meaxure-export
|
|
127
|
+
1. **`meaxure-export`**(index.html 内嵌 artboards + preview/ + assets/)→ **禁止拿 preview 整图建卡**,先经 sketch-spec-to-card 前处理:
|
|
205
128
|
```bash
|
|
206
|
-
#
|
|
129
|
+
# 解释器:下面示例写 python3,按本机可用者替换(python3 / python / py)——脚本侧统一解析
|
|
130
|
+
# 见 scripts/lib/python.mjs(Windows 的 python3 常是 Store 假别名,只有 py 启动器时用 py)
|
|
131
|
+
# ① 列画板请用户选范围(铁律 §0-13):不带范围直接跑 parse 会 exit 4 打印 1..n+全部 清单
|
|
207
132
|
python3 skills/sketch-spec-to-card/scripts/parse_meaxure.py --src <导出目录> --list
|
|
208
|
-
# ②
|
|
133
|
+
# ② 用户回序号 k → --indices <k-1>;回「全部」→ --scope-all(UI 产物全量;产卡视为显式批量授权)
|
|
209
134
|
python3 skills/sketch-spec-to-card/scripts/parse_meaxure.py --src <导出目录> --draft <稿名> --build --indices <k-1>
|
|
210
135
|
python3 skills/sketch-spec-to-card/scripts/cluster_states.py --out UI/<稿名>
|
|
211
136
|
```
|
|
212
|
-
产出 `UI/<稿名>/`
|
|
213
|
-
2. **`ui-bundle
|
|
214
|
-
3. **`image
|
|
215
|
-
4. **`card-dir
|
|
216
|
-
|
|
217
|
-
> **路由原则**:MeaXure 导出是「多画板 + 标注」的批量输入——卡片聚焦裁切、多卡分离、弹窗/气泡识别、切图收集都是 `sketch-spec-to-card` 的专职能力。跳过它直接读整图,等于放弃聚焦边界与标注数值,还原度必然受损。故 `kind=meaxure-export` 且 `preprocess.needed=true` 时,**先跑上游管线再生成,不允许"先建一张看看"**。
|
|
218
|
-
>
|
|
219
|
-
> `route_input.mjs` 退出码:0 = 已路由;3 = `unknown`(判不出形态);1 = 用法/路径错误。拿到 `unknown` 时不要猜形态,先向用户确认输入。
|
|
220
|
-
>
|
|
221
|
-
> **多画板选择门禁(铁律 §十三)**:判出 `meaxure-export` / `ui-bundle`(多画板)后,**UI 产物可全量生成**(前处理一次跑完整份导出),但**产卡前必须锁定单个画板 / 单个 cardKey**——用户未指定时先机械列清单(`parse_meaxure.py --src <导出目录> --list`,或 `UI/<稿名>/manifest.json` 的 `canvases[]`、`clusters.json` 的 `cards[]`)按 **`1..n` 编号列出(序号 1 起)+ 末尾追加 `全部`**;**没有弹选项工具**(不存在 `request_user_input`,**不要去调用或寻找**),一律在正文列出清单 + 一句纯文本提问后**停止输出、等用户回序号**。**UI 产物可回 `全部` 全量生成**;**产卡默认单画板 / 单 cardKey**,用户回 `全部` 才算显式批量授权。**禁止**自行挑画板、禁止未经同意批量产卡。选定后再进 Workflow A / A.5。详见 `references/rules.md §十三`。
|
|
222
|
-
|
|
223
|
-
> **快路径总则**:建卡前先 `route_input.mjs <输入路径>` 定入口(`meaxure-export` 必须先经 `sketch-spec-to-card` 前处理,见 Workflow 0),再 `resolve_card_template.mjs <意图>` 查模板库(命中即 `--from` 克隆跳过生成);未命中走 Workflow A 六步闭环——AI 读图 + `spec_tree.mjs` 理解布局 → `scaffold_card.mjs` 出骨架 → `add_component.mjs` 逐区填充 → **validate + lint 双门禁**(结构合法性 + 行为规则零 ERROR)→ `render_diff.mjs` 视觉对比修正(核心闭环)→ 交付。交付时判断:本卡是否首次出现的布局/交互模式?是则跑 `register_card_template.mjs --id <cardId> --check`,确认新颖后经用户同意登记入模板库。改卡用 `add_component.mjs` / `card_node_models` 定位;范式读 `recipe_snippets/`;校验-修复用 `autofix_schema.py` 压成 1 轮。
|
|
224
|
-
>
|
|
225
|
-
> **⚡ 输出格式(P0 优化,token 关键)**:`schema.json` 是编辑器持久化格式(单卡可达百 KB,充斥可推导 `itemId` / 空 `itemDefaultValue` / 空数组)。**AI 不要直接吐完整 schema**——改为输出 **紧凑 IR(Intermediate Representation)**,再由 `expand_ir.mjs` 展开成完整 schema(内置 `itemId` 推导、UI 同目录切图汇聚、`validate`/`lint` 双门禁)。节点树实测压缩 **4.4–4.8x**,建新卡省略 `dictionary` 整体省 **78–81%** token,视觉闭环每轮也只传 IR。字段契约 + 示例见 `references/ir-format.md`;上游 `sketch-spec-to-card/scripts/build_prompt.py` 已向 AI 下发同一 IR 契约。
|
|
226
|
-
|
|
227
|
-
> **设计稿归档(自动)**:生成卡片时,脚本会自动把对应的 `card-*.png` 复制到卡片目录并重命名为 `<卡id>.png`(复制而非移动,UI 原件保留)。`iterate.mjs` 用 `--design` 的 `card-N.png`;`expand_ir.mjs` 支持可选 `--design`;`generate_cards.mjs` 按多卡序号自动匹配画板内 `card-N.png`。最终卡片目录形如 `src/cards/<id>/{schema.json, data.json, <id>.png}`。
|
|
228
|
-
|
|
229
|
-
### Workflow A — AI 读图 + 工具辅助 + 视觉闭环(推荐路径)
|
|
137
|
+
产出 `UI/<稿名>/` 要素包(card-N.png + spec.json + prompt.md + slices/ + manifest/clusters)后按入口 ② 走 Workflow A。幂等:manifest export 已匹配则跳过管线直接给存量产物。
|
|
138
|
+
2. **`ui-bundle`**(card-N.png + spec.json + prompt.md 或含 manifest 稿目录)→ 列清单选定单画板/cardKey(§0-13)→ Workflow A;subcard/overlay_dialog 按 A.5 分流。
|
|
139
|
+
3. **`image`**(单图)→ Workflow A 纯视觉;若图来自某 MeaXure 导出,改传导出目录走入口 ①。
|
|
140
|
+
4. **`card-dir`**(含 schema.json)→ 改卡,Workflow B。
|
|
230
141
|
|
|
231
|
-
|
|
142
|
+
> 退出码 0 已路由 / 3 unknown(**先问用户别猜**)/ 1 用法错 —— 完整退出码语义见 `skills/shared/exit-codes.md`(权威;3 属 `needs-user`,**不是脚本报错**)。meaxure-export 且 preprocess.needed=true 时**不允许"先建一张看看"**——跳过前处理等于放弃聚焦边界与标注数值。
|
|
232
143
|
|
|
233
|
-
|
|
234
|
-
> | 角色 | 工具 | 用途 |
|
|
235
|
-
> |---|---|---|
|
|
236
|
-
> | **AI 主判** | 读 `card-1.png` + `spec_tree.mjs` 输出 | 理解布局层级、识别语义区、判断组件映射 |
|
|
237
|
-
> | **构建** | `scaffold_card.mjs` → `add_component.mjs` | 机械组装骨架、逐个插入组件(自带离线硬校验) |
|
|
238
|
-
> | **校验(双门禁)** | `validate_schema.py` + `lint_card.mjs` → `autofix_schema.py` | 结构合法性(validate 0 ERROR)+ 行为规则(lint 0 ERROR:flexShrink/格式/Icon click/R9 等)→ 自动修 itemValueFrom/itemId |
|
|
239
|
-
> | **视觉闭环** | `render_diff.mjs` | 渲染 vs 设计稿并排对比 → AI 看差异 → 修正 → 再对比 |
|
|
144
|
+
### Workflow A — AI 读图 + 整树 IR + 视觉闭环(唯一建卡主路径)
|
|
240
145
|
|
|
241
|
-
|
|
146
|
+
分工:**AI 主判「看图理解布局 + 语义裁决」**,工具做「机械构建 + 校验 + 渲染」。层级由 `spec_tree.mjs` 从 elements 矩形包含关系几何重建(MeaXure layers 图层树≠卡片拓扑,已废弃)。
|
|
242
147
|
|
|
243
|
-
|
|
148
|
+
**语义裁决协议(AI 主判,脚本只提名)**:每个可见簇归入 `static-text / display-value / input / action / navigation / list / media / decoration`;记录「视觉形态 + 标注几何 + 预期交互」三类证据,≥2 信号一致才定稿,冲突以截图中可交互控件与内容承载方式优先;裁决留痕进训练报告/lessons,禁写 schema 非 DSL 字段。**细则(展示值 vs 输入值/单一消费/分段壳/文字底壳/重复控件归模板/间距只计一次/高度内容撑开/媒体降级/垂直节奏等)见 `references/semantic_adjudication.md`(步骤 1 前必读)**。
|
|
244
149
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
```text
|
|
248
|
-
static-text / display-value / input / action / navigation / list / media / decoration
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
裁决必须同时记录三类证据:视觉形态、标注几何、预期交互。至少两个信号一致才可定稿;冲突时以截图中的可交互控件和内容承载方式优先,层级名称只作参考。特别约束:
|
|
252
|
-
|
|
253
|
-
- **展示值 vs 输入值**:大号货币符号 + 数字 + 右侧编辑/箭头控件,应判为 `input`;用 `Input` 承载数值,货币符号独立为 Text 前缀。输入框高度读标注或按字号行高推导,不得写死整卡高度。
|
|
254
|
-
- **单一消费**:一个源文本只能被一个语义块消费。列表标题、按钮文案、主金额、辅助文案不得重复渲染;发现重影时先检查语义块重叠消费,再调样式。
|
|
255
|
-
- **分段壳只消费一次**:顶部小高度壳若几何包含两个及以上 Tab 文本,按 segmented control 处理,不再同时作为顶部装饰背景。控件高度用「文字上边距 × 2 + 文字高度」推导,行与子项显式垂直居中;选中/未选中底色优先读壳和标注,缺失时按标注缺陷降级。已导出且像素身份可信的 Tab 背景切片作视觉层,其内置文字不得再显示一遍;保留透明 Text 只作为无障碍与点击状态层。
|
|
256
|
-
- **文字底壳跟随标注**:文字外缘附近的小型纯色 shape 是该文本的背景壳;宽度、高度、圆角和颜色必须一起迁移到包裹容器,不能只还原文字。大面板、列表壳和顶部整卡壳不得因局部包围关系被误判为文字底壳。
|
|
257
|
-
- **几何顺序**:顶层语义块按标注 y 插入,不按脚本段落顺序输出。同行判定必须消费原始标注元素;主金额合成片段不得复用为组标签;列表/重复媒体带内的分隔线留在项模板里,不提升为顶层 divider。
|
|
258
|
-
- **重复控件归模板**:同一右缘、同尺寸、等距重复的小控件是列表/重复行模板的一部分;必须由 ListLayout/重复项模板承载,禁止同时作为孤立媒体块再次渲染。副金额、按钮、表单值等已消费文本也必须从列表标题候选中互斥排除。
|
|
259
|
-
- **间距只计一次**:相邻语义块的标注间距不能同时塞进上一块底部和下一块顶部。列表标题、列表项和查看更多必须注册语义边界;列表行内边距由“标注行高 - 内容高”推导,ListLayout 行间距显式归零。
|
|
260
|
-
- **缺失容器高度用子元素推导**:面板标注缺 height 时,取已消费子元素最大底沿加面板 padding 作为语义底沿;后续按钮、标题和列表间距按最近底沿计算,不用段落级“上一文本”跳过中间媒体。
|
|
261
|
-
- **高度由内容撑开**:Root/普通容器用 `auto`;Input、Image、Icon、Divider 和单行 Text 等叶子控件允许从标注读显式高度。Text 高度来自标注 rect,不改 `lineHeight`;纵向节奏仍由容器 padding 控制。
|
|
262
|
-
- **媒体缺陷降级有序**:紧凑媒体缺导出切图时先消费上游 `cropSlice`(从原画板局部裁切的证据),失败才用 `http://iph.href.lu/{w}x{h}?text=...` 占位图;不要用纯色块伪装成图片。弥散、光晕、噪点和不规则纹理属于位图证据,不能用纯色或规则 CSS 渐变近似。宽幅/大面积背景是特例:没有可靠导出切片时禁止画板裁切(会带上前景文字),用标注近似纯色兜底并标记 `background-asset-unavailable` 留给人工补图;训练只局部遮罩该背景矩形,文本、组件和其余像素继续考核。独立细线必须映射 `Divider` 并保持逻辑 `1px`;ListLayout 必须显式声明 `row-spacing=0` 与 `edge-insets={0,0,0,0}`,重复项模板继承标注字号/字重/颜色。
|
|
263
|
-
- **面板重叠有界修正**:只有轻微重叠可把面板流式高度截到下一重叠顶边,且不超过 `max(16px, 25% 面板高度)`;列表等完整业务容器不裁剪。所有 `Text` 保持不可压缩,对齐决定辅助 padding 只落在必要一侧。
|
|
264
|
-
- **垂直节奏用 padding 不用 lineHeight**:渲染器文字行高 = `fontSize × 1.5`(实测;标注给了 lineHeight 就直接设,见 ui_fidelity_rules.md §15),设计稿 `rect.height` 比率在 1.27-1.50 间波动;控制元素垂直位置时优先通过容器 `paddingTop/paddingBottom` 调整,**不设 `lineHeight`**——设 lineHeight 会触发 flex 重新分配空间,简单卡片内容会被拉伸到整个卡片高度。区块间距从 `semanticTopGap(y)` 推导(= 当前块 y - 上一个语义块 bottom),确保渲染内容带 y 位置与设计稿对齐。列表项行内 padding 由「标注行高 - 内容高」÷2 推导,不用固定 token 兜底。
|
|
265
|
-
- **裁决留痕**:语义结论写进训练报告或 lessons,不写入 schema 的非 DSL 字段。
|
|
266
|
-
|
|
267
|
-
**步骤 1 — 理解(AI 多模态)**:
|
|
150
|
+
**步骤 1 — 理解**:
|
|
268
151
|
```bash
|
|
269
|
-
#
|
|
270
|
-
node scripts/spec_tree.mjs --spec UI/<画板>/spec.json --card 1
|
|
271
|
-
# 同时查看 card-1.png(设计稿聚焦图)
|
|
152
|
+
node scripts/spec_tree.mjs --spec UI/<画板>/spec.json --card 1 # 层级树;同时读 card-1.png 聚焦图
|
|
272
153
|
```
|
|
273
|
-
AI
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
154
|
+
AI 输出 3-5 行中文布局理解(顶部…/中部…/底部…)。
|
|
155
|
+
|
|
156
|
+
**要素盘点 + 列表数组化计划(步骤 2 之前必须落定,2026-09-25)**:基本要素齐全是像素自迭代的前提。
|
|
157
|
+
布局理解输出里必须包含:① **全类型要素计数**——文本 / 图标(symbol)/ 分割线(细长条 shape)/ 切图 / 图表 / 形状装饰,
|
|
158
|
+
逐类清点(后续 `check_fidelity` 的 `elements.symbols/shapes` 与 readiness 会按同口径对账,漏建会被点名);
|
|
159
|
+
② **列表数组化计划**——`spec_audit` 的 `listCandidates[]`(同构重复行 / tile,值逐行不同)逐条回应:
|
|
160
|
+
数组变量名(照 values 列语义化命名)+ 字段清单 + 来源提名序号;设计稿里重复出现的数据行**禁止逐行静态展开**
|
|
161
|
+
(数据绑定齐全是硬前提:readiness 会拦「列表语义数组零消费」与「提名了列表却零数组化」,见步骤 3 门 G;
|
|
162
|
+
范式 `ir-format.md` §2e + `recipe_snippets/list-expand-collapse.json`);
|
|
163
|
+
③ **图表范式计划**——盘点出图表(雷达 / 环形 / 仪表盘 / 柱状 / 折线 / 散点)≥1 时,逐图写明
|
|
164
|
+
「范式来源三件套」:recipes.md 图表章节锚点 + `recipe_snippets/canvas-*.json` 片段 + card_index.json 近邻图表卡。
|
|
165
|
+
IR 下发前任一件缺位 = 要素盘点未完成(**禁止**用 Text/Image 堆砌模拟图表——像素与 token 双输),
|
|
166
|
+
Canvas 自绘范式与数据契约见 `ir-format.md` §2f 末段;
|
|
167
|
+
④ **宽度自适应计划**——顶层 width 写卡面宽(非画板宽);占满父内容盒的容器用 `100%`/不写宽
|
|
168
|
+
(lint `r66-fullwidth-px` error),px 只给图标 / 头像 / 徽章 / 图表画布等真固定元素(`ir-format.md` §2f)。
|
|
169
|
+
|
|
170
|
+
**步骤 2 — 整树 IR 一次下发(唯一主路径)**:一次性写出整卡紧凑 IR(契约 `references/ir-format.md`;节点树压缩 4.4-4.8x,省 token 78-81%)再机械展开:
|
|
277
171
|
```bash
|
|
278
|
-
node scripts/
|
|
172
|
+
node scripts/expand_ir.mjs --ir .cache/ai-scratch/<卡id>.ir.json --out src/cards/<卡id>/
|
|
279
173
|
```
|
|
280
|
-
|
|
174
|
+
- 1 次下发替代 O(N) 次 add_component 往返(单卡 20+ LLM 回合的主因);add_component 退役为改卡专用,scaffold 仅存 blank 调试;截断/大卡 `ir_merge.mjs` 分片(幂等+原子,**小卡禁拆**——每片 +40-140s;支持 `{parts:[…]}` 捆绑包:一次 fs_write 写多片 + 一次 merge 全收,幂等粒度=整包文件名)。
|
|
175
|
+
- 样式值从 spec element style 读不猜;运行期数据必须绑 inputParams(rules.md §三);中文+数字混排按 rules.md §十四拆「静态文案+数字变量+表达式」。
|
|
176
|
+
- 视觉迭代修改用 `ir_patch` / `iterate.mjs --set` 点路径修,**不整份重写 IR**(`references/iteration_protocol.md`)。
|
|
281
177
|
|
|
282
|
-
**步骤 3 —
|
|
283
|
-
AI 从 `spec_tree.mjs` 输出的层级树逐区读取子元素 → 每个区域用 `add_component` 逐个插入:
|
|
178
|
+
**步骤 3 — 内容就绪门禁(S4.9,**像素循环的前置条件**)**:
|
|
284
179
|
```bash
|
|
285
|
-
node scripts/
|
|
180
|
+
node scripts/readiness.mjs --id <卡id> --spec UI/<画板>/spec.json --design UI/<画板>/card-N.png --json
|
|
181
|
+
# 退出码 0=就绪 / 3=未就绪(**3 不是脚本报错,是内容没准备好**,kind=not-ready)/ 1=用法错误
|
|
182
|
+
# 完整退出码语义(含各脚本的 gate-fail / needs-user / diagnostic)见 skills/shared/exit-codes.md
|
|
286
183
|
```
|
|
287
|
-
|
|
184
|
+
七道判定(前五道是 **schema 侧**声明性判定,不需要渲染 ⇒ 挡在最贵的一步之前;第六道是 **spec 输入侧**契约检查,只在传了 `--spec` 时跑):**A** 组件契约(属性键/样式组/样式子键必须在 `component-meta.json` + `style-meta.json` 白名单内)· **B** 要素齐全(文本逐条对账;另有 `elements.symbols/shapes` 图标与分割线数量对账,缺口进迭代报告 `gate.elementHints` 每轮自查)· **C** 变量绑定完备(`$var` 的根变量必须真存在;**且列表语义数组不允许零消费**——`arraysUnconsumed.hard` 即 blocker,列表数据必须数组绑定)· **G** 列表提名闭环(传 `--audit` 时:S2 审计 `listCandidates` 提名了列表而 schema 数组化列表为 0 ⇒ blocker;提名>数组化只记 note)· **D** 图片地址已配置(每个 `Image` 必须有非空 `value`)· **E** 切图路径已配置(每个 `/slices/...` 引用在 `src/slices` 有对应文件)· **F** 上游产物契约(`spec.json` 的 `cards[<i>].mask` / `rect` 必须存在,仅指 `cards` 非空时;契约 `skills/shared/spec-contract.md` —— 缺 `mask` 多为旧版 spec 产物,下游会静默取默认圆角,须回上游重跑而非在下游加兼容分支。注意 **`cards=[]` 不是错误**:`text_only` / `overlay_dialog` 两类本就不单独产卡(由父卡承载),`artboardType=card` 的「0 卡 · 结构丰富」是上游已知态,须走整图 / AI 读图建卡;**`subcard` 自 2026-09-24 起由上游产 1 张卡**(底部抽屉面板几何直取,`focusSkipReason` 仍为 `bottom_sheet_geometry`)—— 若 `subcard` 仍 `cards=[]` 即旧版产物,回上游重跑。这三类空 `cards` 只记 `checks.spec.notes`,不阻断)。
|
|
185
|
+
|
|
186
|
+
`blockers` 非空 ⇒ **先补内容,别进步骤 5**。理由:内容没齐时像素分毫无参考价值。实测(2026-09-24 gen-1)跳过这步,在 `Image` 的图片地址都没配(属性键写成 `image`,合法键只有 `value` ⇒ 运行时整条静默丢弃 ⇒ 破图)的情况下连刷 10 轮像素,两个回合 623 万 prompt token 全部作废。
|
|
288
187
|
|
|
289
|
-
|
|
188
|
+
`iterate.mjs` **每轮自动再跑这道门禁**:未就绪时本轮**不 render、不 pixelDiff、不消耗迭代轮次**,报告 `gate.stage=content` + `gate.blocked=true` + `blockedAt.{stage,blockers,hint}`。按 blockers 补齐内容后直接重跑 iterate;被挡时禁止反复重跑空转,更禁止去调像素。逃生门 `--no-readiness`(或 `DSL_CARD_SKIP_READINESS=1`)仅 debug 用。
|
|
189
|
+
|
|
190
|
+
**步骤 4 — 校验门禁(渲染前必须全过)**:
|
|
290
191
|
```bash
|
|
291
|
-
#
|
|
292
|
-
python3 scripts/validate_schema.py src/cards/<id>/schema.json # 必须 0 ERROR 0 WARN
|
|
293
|
-
node scripts/derive_data_json.py src/cards/<id>/schema.json --check # data.json 一致
|
|
294
|
-
python3 scripts/autofix_schema.py src/cards/<id>/schema.json # 一键补 itemValueFrom(如有遗漏)
|
|
295
|
-
|
|
296
|
-
# 门禁 2:行为规则(渲染前拦截格式错误,避免到截图才发现)
|
|
297
|
-
node scripts/lint_card.mjs --id <卡id> # 必须 0 ERROR
|
|
298
|
-
node scripts/preflight.mjs --spec UI/<画板>/spec.json --id <卡id> # 必须 0 ERROR(一键 10 项机械检查)
|
|
192
|
+
node scripts/gate.mjs --id <卡id> [--spec UI/<画板>/spec.json] [--json] # ⚡ autofix→validate→derive→lint→preflight 一条命令,任一 ERROR exit 1
|
|
299
193
|
```
|
|
300
|
-
|
|
301
|
-
> **lint 双门禁不可跳过**。lint 现已把以下规则从 WARN 升级为 **ERROR**(渲染前拦截,不等到截图阶段才发现):
|
|
302
|
-
> - **R17**:叶子节点(Text/Icon/Image/MultiText)缺 `flexShrink:0` → 渲染器默认 `flexShrink:1` 会压缩元素(文本换行/图标变形)
|
|
303
|
-
> - **R22**:`width:100%` + `flexShrink:0` 冲突 → 固定宽兄弟被挤出
|
|
304
|
-
> - **R35**:受外宽约束(width 非 auto)的 Row/Column 有 2+ 并列子节点且全部 `flexShrink:0` → 定宽累加溢出
|
|
305
|
-
> - **R-FMT1**:borderRadius 用元组格式 `{12,12,12,12}` → 渲染器无法解析,应为标量 `"12"`
|
|
306
|
-
> - **R-FMT2**:padding/margin 用元组格式 `{16,0,12,0}` → 预览器解析失败,应拆为单独属性
|
|
307
|
-
> - **R-FMT3**:Icon 缺 click eventaction → onClick 双触发
|
|
308
|
-
> - **R-FMT4**:MultiText itemList 项 `itemValueFrom:"1"` 缺 itemDefaultValue → 渲染空
|
|
309
|
-
> - **R9/R10**:Root(view)设非零 padding/margin → 裁切后间距归零铁律
|
|
310
|
-
> - **R38**:任何节点 marginTop 为负值 → 标题/文本与装饰条重叠必须用 AbsoluteLayout + position.top(pitfalls §R42)
|
|
311
|
-
> - **R43**:卡片背景透明 → 必须设非透明背景色,优先从标注 cardFill 取色,缺失则从截图采样(pitfalls §R43)
|
|
312
|
-
> - **R44**:borderRadius/border/shadow 有值但缺类型开关(borderRadiusType/isBorder/isShadow)→ 值被静默丢弃,渲染无效果(pitfalls §R44,expand_ir 自动补)
|
|
313
|
-
> - **R45**:元素宽度靠直觉猜或依赖默认(Row 默认 100% 撑满)→ 必须从标注或截图像素扫描实测(pitfalls §R45)
|
|
314
|
-
> - **R46**:装饰元素写死固定宽度而不绑定表达式 → 与文本联动的装饰条应表达式化(pitfalls §R46)
|
|
315
|
-
> - **R47**:视觉迭代盲目改间距而不先像素分析 → 必须先像素扫描定位差异根因再改(pitfalls §R47)
|
|
316
|
-
> - **R48**:根节点核心样式属性(gap/background/padding/borderRadius)缺失显式默认值 → expand_ir ensureRootDefaults 自动补入(仅根节点)(pitfalls §R48)
|
|
317
|
-
> - **R50**:slotScope 内绑定用 `$$.field` 而非 `$field` → 冗余写法,应为 `$fieldName`(lint 拦截)
|
|
318
|
-
> - **R51**:customAction 读 `this.data.<key>`(key 未被任何 Input value 绑定)→ this.data 仅用于 Input 实时输入值,运行态变量一律 `this.state`(lint ERROR 拦截)
|
|
319
|
-
> - **R52**:v-show 显隐设置显示名 `condition.name` 缺失/为空(validate ERROR,必填不能为空);命名不合规——表达式 <15 字符应与表达式一致、>=15 字符应设合适命名不得抄表达式(lint WARN 提醒)
|
|
320
|
-
> - **R53**:MultiColumn/ListLayout/GridLayout/AbsoluteLayout/Canvas/Map/Video/ViewContainer 直接设 v-show 显隐条件 → 铁律要求外套一层 Row/Column 并把 v-show 设在包裹层(lint ERROR 拦截);其他节点可直接设置
|
|
321
|
-
> - **R54**:ListLayout/GridLayout item 事件直接改绑定数据(this.setData/setRootData/state 赋值)→ 铁律要求 `postMessage('globalSet', patch)`(patch 与 setData 入参一致)+ 根节点 onReady `addEventListener('globalSet')` 代写;用 globalSet 但根无监听同样 ERROR(lint 拦截)
|
|
322
|
-
> - **R55**:customAction 事件脚本出现 `$$`(含 `this.state.$$` / `$$.field` / 「$$ 兜底判断」)→ 铁律要求 slotScope item 字段在事件里直接 `this.state.<field>` 读取(平台保证展开到 state),禁止任何 `$$` 写法(lint ERROR 拦截)
|
|
323
|
-
> - **R57**:`style.other.opacity` 用表达式/绑定(`itemValueFrom:"1"`)→ 移动端不支持透明度表达式,必须走透明度切换固定范式(静态变体 ×N + 等宽高 overflow:hidden 容器 + 事件上移 + 互斥 v-show;`apply_opacity_pattern.mjs` 可机械改写)(lint ERROR 拦截)
|
|
324
|
-
> - **R62**:图表 Canvas 把坐标系/参考线(网格线/轴线/雷达环与辐射线/环形轨道)画在数据标记之上 → 铁律要求出码顺序 = 底 → 顶(参考线最底、数据标记居中、文字标签最顶);半透明数据标记把 opacity 乘进颜色/渐变(代理 ctx 无 globalAlpha)(生成器 `chartPaintLayers` 强制分层 + `tools/tests/chart-layer-order.test.mjs` 护栏)
|
|
325
|
-
- **R56**:customAction 事件脚本用 `window.ynet` 前缀或 `typeof window` 存在性守卫调 JSAPI → 铁律要求直接裸调 `ynet.callJSAPI(name, params, cb)`(ynet 为平台注入全局,无需前缀与守卫)(lint ERROR 拦截)
|
|
326
|
-
> - **R49**:inputParams 缺少必填字段(key/name/type/defaultValue/desc/rule/children)→ validate ERROR;expand_ir 自动补全(pitfalls §R49)
|
|
194
|
+
> **lint(ERROR 级渲染前拦截)**:报错自带规则号与修法,按报告逐条修,无需预背。分类:压缩/溢出(R17/R22/R35/R63/R38)、格式(R-FMT1/2、R44、R49)、交互事件(R-FMT3、R51/R54/R55/R56)、显隐透明(R52/R53/R57)、切图资产(R31b/c)、背景(**R43 禁完全透明,半透明合法**)。**规则条数以脚本为准,本文档不复制数字**(`node scripts/lint_card.mjs --all` 实跑即得)。**code → 文档锚点的唯一权威 = `scripts/lib/rules/registry.mjs`**(每条 code 登记真正对应的 references/ 章节;门禁 `tools/tests/lint-rule-registry.test.mjs` 保证「实现 ↔ 注册表 ↔ 文档锚点」三方对账)——**不要按号直接猜文档**:lint 的 R50–R57 与 `generation_pitfalls.md` 的同号 R 是**两套无关语义**(pitfalls 是训练侧编号),按号查 pitfalls 会查到别的规则。
|
|
327
195
|
>
|
|
328
|
-
>
|
|
196
|
+
> 注意 **R62(图表绘制层序)不是 lint 规则** —— 它要求 Canvas 出码顺序 = 底→顶(网格/轴线 → 数据标记 → 文字标签)。机械保证在 v3 生成器的 `chartPaintLayers`(`lib/v3_shared.mjs`,测试 `tools/tests/chart-layer-order.test.mjs`);AI 手写 Canvas 表达式时 lint 无法可靠解析调用顺序,靠 render 后目视核对 + `diff_bands.mjs`。
|
|
329
197
|
|
|
330
198
|
**步骤 5 — 视觉闭环(核心)**:
|
|
331
199
|
```bash
|
|
332
|
-
# ⚡
|
|
333
|
-
|
|
200
|
+
# ⚡ 一条龙:expand + lint + render + pixel-diff(~2s,快 5×);--set 原子点修 IR
|
|
201
|
+
# --spec 别省:没有它 widthMismatch 宽度基准校验与 contributors 的 designH 都拿不到设计稿口径
|
|
202
|
+
node scripts/iterate.mjs --ir <IR.json> --out src/cards/<卡id>/ --design UI/<画板>/card-1.png --spec UI/<画板>/spec.json --width 343 [--set 'children.0…marginTop="7"']
|
|
203
|
+
node scripts/diff_bands.mjs --id <卡id> --design <card-1.png> --tol 2 # 量化偏差(dy/dh/主色直方图),防肉眼误判
|
|
204
|
+
```
|
|
205
|
+
结果 JSON:`pixelDiff.match` + `hotspots`(>3% 差异热区,--elements 落到具体组件)+ `fidelity` + `stalled` + `contributors` + `structuralGaps`(逐行几乎全异的连续带区——整块漏建/背景错涂的第一信号,存在时先修结构再看微调线索)。逐项修 IR 重跑,**2-3 轮至 match 达门禁线且 lint 0**。
|
|
206
|
+
> **门禁线唯一权威是代码**:`iterate.mjs` 的 `GATE.match`(默认 **95**,可用环境变量 `DSL_CARD_GATE_MATCH` 覆盖)。本行数字仅为说明,改阈值请改 `iterate.mjs:60` 附近那处常量 —— 文档与报告的 `--gate` 判定永远同源,不会出现「文档说 85、门禁判 95」的返工。
|
|
334
207
|
|
|
335
|
-
|
|
336
|
-
node scripts/iterate.mjs --ir <IR.json> --out src/cards/<卡id>/ --design <card-1.png> \
|
|
337
|
-
--set 'children.0.children.2.children.1.s.margin.marginTop="7"'
|
|
208
|
+
> **迭代纪律(硬性;全集 `references/iteration_protocol.md`)**:每卡 ≤15 轮;stalled(连续 3 轮未刷新最好成绩,含震荡下滑)即 `ir_restore.mjs --best` 回退;**三段式门禁逐段推进 —— `gate.stage=content` 先补内容(要素/变量绑定/图片地址/切图落盘,本轮没 render)、`stage=structure` 再补要素与结构、`stage=pixel` 才谈样式像素**;最好成绩判据是 `score = match − 6×缺要素数`(丢要素的一轮不算进步);一轮只改 `contributors[0].elements[0]` 一个属性;多卡连跑 `--keep-alive` 每轮 ~0.6s。
|
|
338
209
|
|
|
339
|
-
|
|
340
|
-
node scripts/diff_bands.mjs --id <卡id> --design UI/<画板>/card-1.png --tol 2
|
|
210
|
+
**步骤 6 — 交付**:validate 0 + lint 0 + 视觉一致即完成;MCP `card_write({id, schema, verify:true})` 完整收口。首次出现的布局/交互模式 → `register_card_template.mjs --check` 新颖性检查,经用户同意登记模板库(§7.5)。
|
|
341
211
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
```
|
|
345
|
-
`iterate.mjs` 单次调用把 expand + lint + render + 像素对比合成一步完成,并输出结构化 JSON(`pixelDiff.match` 百分比 + `lint.errors` 计数 + `render.ms` 耗时)。比逐脚本调用快 **5×**(~2s vs ~8s),消除了 3 次 Node 进程冷启 + 1 次 Chrome 冷启。
|
|
346
|
-
若 `--design` 指向 `card-N.png`,结果 JSON 的 `designImage` 字段同时给出归档后的 `<卡id>.png` 路径。
|
|
212
|
+
> **纯截图建卡(无 spec.json)**:跳过 spec_tree,AI 直接读截图,其余相同。
|
|
213
|
+
> **批量产线**:`generate_cards.mjs --ui <UI目录> --out <目录> [--only <子串>]` 批量粗骨架后逐卡走步骤 5 精修;生成后按 `field_naming.md` 复核字段命名(禁 obj_N/amount_0)。
|
|
347
214
|
|
|
348
|
-
|
|
215
|
+
### Workflow A.5 — 画板分类分流(artboardType)
|
|
349
216
|
|
|
350
|
-
|
|
217
|
+
1. **`card`**:正常 Workflow A;多形态(Tab/条件/表单/时序)按 clusters.json 维度装配。
|
|
218
|
+
2. **`subcard`**(模态子卡):独立 Dialog 卡(pageId `<slug>Dialog`)忠实还原;关闭(glyph `times`)→ closeAlertCard;父卡 alertCard 打开(recipes §2 + `recipe_snippets/alertCard-pair.json`)。上游已为底部抽屉产 **1 张卡**(面板 rect + 顶圆角遮罩 + `card-N.png` + 卡内 `elements`/`segments`)—— 直接按其 `rect` / `mask.radius` 定位还原,**不要**再读整图自定边界。
|
|
219
|
+
3. **`overlay_dialog`**(弹框/toast):**不产卡**——alertDialog 调用补到父卡(clusters.json.overlays[].parentKey)对应事件;文案取上游 prompt.md §3。
|
|
220
|
+
4. **`text_only`**(纯文本板):**不产卡**(上游 status=skipped),勿人工绕过。
|
|
221
|
+
> prompt.md 边界:overlay_dialog=交互提示文档(勿产卡);subcard=常规建卡 prompt;text_only=只写判定依据。
|
|
351
222
|
|
|
352
|
-
|
|
353
|
-
> ```bash
|
|
354
|
-
> node scripts/iterate.mjs --keep-alive
|
|
355
|
-
> # stdin 逐行输入 JSON:{"ir":"...","out":"...","design":"...","width":343}
|
|
356
|
-
> ```
|
|
223
|
+
### Workflow B — 编辑已有卡片
|
|
357
224
|
|
|
358
|
-
|
|
225
|
+
1. 读卡:`card_read(id)` 或直接读 `src/cards/<id>/schema.json`(及 data.json)。
|
|
226
|
+
2. 改结构:`add_component.mjs --id <id> --parent <cid> --className <X> [--text "…"] [--click]` 或 MCP `card_add_component`(自带离线硬校验);`card_node_models(id)` 定位字段。保留未涉及节点与孤儿字段。
|
|
227
|
+
3. 同步数据:增删改 inputParams[] 时 data.json 同步(autofix 或 derive)。
|
|
228
|
+
4. 闭环:`card_write({id, schema, verify:true})`;`card_screenshot(id)` 复核。
|
|
229
|
+
|
|
230
|
+
### Workflow C — AI 快速开发
|
|
359
231
|
|
|
360
|
-
|
|
232
|
+
- 从脚手架/证据起步,绝不从空文件手写;描述**组件组成**而非像素("顶部 Row 放标题+关闭 Icon,下面 ListLayout 列 3 任务")。
|
|
233
|
+
- 闭环:scaffold/改 → `card_write({verify:true})` → 有误 `autofix_schema.py` 1 轮清零 → `card_screenshot` 确认。
|
|
361
234
|
|
|
362
|
-
|
|
235
|
+
## 9. 本地预览工作流
|
|
236
|
+
|
|
237
|
+
- **自包含截图(默认)**:`node scripts/render_card.mjs --id <id> --out render.png` 用 vendor 构建产物 + 系统 Chrome(CDP),随机端口用完即关,不占 5180/8787;产物由根目录 `npm run build:skill-preview` 生成。
|
|
238
|
+
- **宿主 dev server(可选)**:宿主有 `/__cards` `/__card/<id>` 接口时可实时读卡;skill 复制到其他项目不要求这些接口。
|
|
239
|
+
|
|
240
|
+
## 10. 校验脚本
|
|
363
241
|
|
|
364
|
-
|
|
242
|
+
**高频命令**(全集 + MCP 工具 + r057 内部规则 + 四层校验自洽见 `references/scripts_reference.md`):
|
|
365
243
|
|
|
366
|
-
**批量产线(多画板 → 多卡)**:当需要一次性处理多个画板时,可先用 `generate_cards.mjs` 批量生成粗骨架,再对每张卡走步骤 5 视觉闭环精修:
|
|
367
244
|
```bash
|
|
368
|
-
node
|
|
245
|
+
node scripts/gate.mjs --id <卡id> [--spec <spec.json>] [--json] # ⚡ 门禁一条命令
|
|
246
|
+
node scripts/route_input.mjs <输入路径> [--json] # Workflow 0 输入路由
|
|
247
|
+
node scripts/expand_ir.mjs --ir <IR.json> --out src/cards/<卡id>/ # IR→schema/data(建卡主路径)
|
|
248
|
+
node scripts/iterate.mjs --ir <IR> --out <dir> --design <png> [--set 'p=v'] # 一条龙视觉闭环
|
|
249
|
+
node scripts/spec_tree.mjs --spec <spec.json> [--card 1] [--compact] # 层级树
|
|
250
|
+
node scripts/lint_card.mjs --id <卡id> | --all [--json] # 行为规则体检(条数以实跑为准)
|
|
251
|
+
node scripts/diff_card.mjs --id <卡id> [--baseline <path>] # 变更对比(整体替换后必跑)
|
|
252
|
+
node scripts/check_fidelity.mjs --spec <spec.json> --schema <schema.json> # 保真门禁(npm run check:fidelity)
|
|
253
|
+
node scripts/render_card.mjs --id <卡id> [--keep-alive] # 离线截图
|
|
254
|
+
node scripts/v3_regression.mjs [--update-baseline] [--cases <path>] # v3 回归门禁(金标清单 training/pass1/cases.json)
|
|
369
255
|
```
|
|
370
|
-
> **字段命名复核(生成后必做)**:通读 `dictionary.inputParams` 与设计稿标签,确认每个 key 语义化(camelCase 英文,禁止 `obj_N`/`amount_0` 序号名)。词典 `references/field_name_dict.json` 覆盖通用标签;新业务标签按实际含义补语义化 key。命名规则见 `references/field_naming.md`。
|
|
371
|
-
### Workflow A.5 — 消费 `sketch-spec-to-card` 的画板分类(overlay_dialog / subcard / card)
|
|
372
256
|
|
|
373
|
-
|
|
257
|
+
## 11. 参考路由(分级按需加载,勿全量读)
|
|
374
258
|
|
|
375
|
-
|
|
376
|
-
2. **`subcard`(带标题+关闭按钮的模态子卡 → alertCard 父子卡)**:
|
|
377
|
-
- 生成为一张独立 **Dialog 卡**(pageId 建议 `<slug>Dialog`),切图/样式按子卡自身内容正常还原(忠实设计稿)。
|
|
378
|
-
- 标题栏关闭按钮(×,glyph `times`)→ `closeAlertCard`;父卡(上游 `clusters.json` 的 `parentKey` 或 `prompt.md §6`)用 `alertCard` 打开。范式见 `recipes.md §2` + 片段 `recipe_snippets/alertCard-pair.json`。
|
|
379
|
-
3. **`overlay_dialog`(弹框/确认框/消息提示/toast → alertDialog JSAPI)**:**不生成独立卡片**。将该画板对应的 `alertDialog` 调用补到**父卡**(上游 `clusters.json.overlays[].parentKey` / `prompt.md §4` 指示的触发卡)的对应按钮 / 条件事件中。文案取自上游 `prompt.md §3` 提取的 title/message/按钮;视觉不必还原,以平台原生弹框为准。范式见 `recipes.md §12` + 片段 `recipe_snippets/alertDialog-call.json`。参考存量 `budgetAnalysis`(温馨提示)、`creditCardPayment`(还款前二次确认)。
|
|
259
|
+
> **v3 演进纪律(冻结启发式增长)**:v3 识别不了/识别错的新布局模式 → ① sem 决策回路(`--sem-dump` + `--decisions`,patterns §20)② AI 视觉主判走 Workflow A ③ 仅 ≥3 卡共性缺陷才改 extract 层且必跑 `v3_regression.mjs`(金标在仓库 `training/pass1/cases.json`,skill 不持业务路径)。lessons.jsonl(solidified 已标注)属 P2 档案,生成上下文不加载。
|
|
380
260
|
|
|
381
|
-
|
|
261
|
+
**P0 生成必读**:`quickref.md`(一页纸速查)+ `ui_fidelity_rules.md`(还原度规则)+ `component_rules.md`(组件硬约束)。
|
|
382
262
|
|
|
383
|
-
|
|
263
|
+
**P1 按场景**:`rules.md`(铁律全集)|`dsl_structure.md`(结构/itemId 全表)|`component_specs.md`(组件骨架)|`expression_engine.md`($ 引擎)|`amount_formatting.md`(金额)|`event_patterns.md` + `platform_jsapi.md`(事件/JSAPI)|`field_naming.md`(命名)|`recipes.md` + `recipe_snippets/`(范式)|`previewer_contract.md`(预览器契约)|`spec_to_schema_patterns.md`(v3 范式 + §20 决策层)|`iteration_protocol.md`(迭代协议)|`semantic_adjudication.md`(语义裁决细则)|`scripts_reference.md`(脚本全集)|`slices_convention.md`(切图)|`image_to_card.md`(图片管线)|`message-center-pattern.md`(消息中心)|`image_diff.md`(视觉清单)|`card_to_summary.md`(反向描述)|`card_index.json`/`card_templates.json`(路由索引)。
|
|
384
264
|
|
|
385
|
-
|
|
386
|
-
2. 改结构:用 `node scripts/add_component.mjs --id <id> --parent <componentId> --className <X> [--text "文案"] [--click]` 插新组件,或直接调 MCP `card_add_component({id,parent,className,text,click})`(插入后自带离线硬校验);或按 `card_node_models(id)` 定位字段改值。保留未涉及节点与孤儿字段。
|
|
387
|
-
3. 同步数据:增删改 inputParams[] 时 data.json 同步(autofix 或 derive)。
|
|
388
|
-
4. 闭环:`card_write({id, schema, verify:true})`;`card_screenshot(id)` 复核视觉。
|
|
265
|
+
**P2 改脚本/排查**:`generation_pitfalls.md`(132KB 事故档案,**训练侧编号体系**,与 lint 的 code 不是一套——查 lint 规则用 `scripts/lib/rules/registry.mjs`;已固化进 lint/expand_ir/autofix 的条目机械拦截,生成时无需预读)。
|
|
389
266
|
|
|
390
|
-
|
|
267
|
+
## 12. 重要边界
|
|
391
268
|
|
|
392
|
-
-
|
|
393
|
-
-
|
|
394
|
-
-
|
|
269
|
+
- 生成避坑清单(itemValueFrom 必填、style itemId 权威来源、图片解析、布局陷阱、Playwright 视觉验证、**进度条必须数据驱动**)见 `generation_pitfalls.md`(§8 进度条:绑定 ≤1 比率变量映射宽度,禁静态写死百分比)。
|
|
270
|
+
- 不要仅凭 palette/源码注册就声称组件或 action 可用;生成前要求有导出 JSON 形状。6 个编辑器专属类预览不渲染。
|
|
271
|
+
- actionType 已验证值:customAction/startRouter/closeAlertCard/sendAiChatMessage;alertCard/showPicker/showToast 等是 JSAPI 调用,不是 actionType。
|
|
272
|
+
- 优先复用 src/cards/*/schema.json 结构,按模式选近邻参考;改已有 schema 除非真新增组件,否则保持 componentId 稳定。
|
|
273
|
+
- 不要把导出里的未知字段"归一化"掉;保留并告警,直到平台语义明确。
|
|
274
|
+
- data.json 必须从 inputParams[].defaultValue 逐字节可派生;itemValueFrom:"1" 必须**带 itemDefaultValue**(否则渲染空)。
|
|
275
|
+
- Canvas onMeasured 的 event.canvas 是**设计稿坐标系**(已按 scale 换算),绘图用逻辑设计 px,不要乘 devicePixelRatio。
|
|
395
276
|
|
|
396
|
-
|
|
277
|
+
---
|
|
278
|
+
### large currency value with right edit affordance rendered as (r018n 训练回灌)
|
|
279
|
+
> lesson: `LESSON-20260825-036` status: `promoted`
|
|
397
280
|
|
|
398
|
-
|
|
399
|
-
- **宿主 dev server(可选集成)**:若宿主项目另有 `npm run dev`(vite,--mode cb)预览服务器 + `/__cards` `/__card/<id>` `/__save` `/__sync` 接口,可实时从磁盘读卡片(GET `/__card/<id>`),不缓存;卡片列表走 GET `/__cards`。alertCard 也实时读目标卡 `/__card/<cardCode>`。改 schema.json / data.json 后刷新即可。复制本 skill 到其他项目时不要求这些接口。
|
|
281
|
+
货币符号 + 数值 + 右侧编辑/箭头控件是金额输入候选;Agent 复核后用 Input + 独立货币前缀,控件高度读标注或行高推导。禁止用业务词触发该规则。
|
|
400
282
|
|
|
401
|
-
## 10. 校验脚本
|
|
402
283
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
2. **文字底壳全覆盖**:普通辅助文案、金额后文案和同行头部文案共用同一底壳/高亮壳消费路径。小于文字高度的底色条映射为文字容器内的底部渐变高亮,不丢弃、不另画独立色块。
|
|
407
|
-
3. **透明形状样式不丢**:按钮或形状的 `opacity` 必须进入 CSS 颜色/渐变;预览器不保证消费组件级 opacity 时,应把透明度乘入渐变 stop。
|
|
408
|
-
4. **全卡渐变形**:覆盖卡片 90% 以上的渐变形映射为卡片容器 `backgroundGradient`,禁止塞进固定高度顶部装饰容器,避免内容被裁切。
|
|
409
|
-
5. **语义前缀外置**:展示层动作前缀只允许来自字段词典配置;生成器逻辑不得内置行业名词、风格名或卡片名。
|
|
410
|
-
6. **行内值几何三规则**(r147):① 行内左对齐值行(label 与值同侧 flex-start 流)的右 padding 恒为 0——值右缘只是内容的自然结束位置,按值缘推 padding 会把可用宽度压窄造成文本裁切;② 多行值(值高 > 1.6×字号)的标签与值首行顶对齐(align: flex-start),居中会把标签推到值块中部;③ 值文本右侧紧邻(≤40px)的小图标是行内尾随图标(值流一部分),值列须 hug 内容渲染,图标紧随值右沿而非行右缘——区别于贴卡片右缘的行尾 affordance。
|
|
411
|
-
7. **文字壳三态**(r147):文字底壳按 spec 分三态——填充壳(backgroundShell,壳 fill 的 **opacity 必须乘入背景色**,半透明红壳=粉徽章底,丢 alpha 会变实色块吞掉同色文字)、描边壳(outlineShell,isBorder+圆角 pill,如标题行右侧的描边操作钮)、高亮壳(highlightShell,文字底部渐变高亮)。同行分组判定:y 容差 或 垂直中心差 ≤ 较矮元素高度×0.75(大小字号混排的同一视觉行)。
|
|
412
|
-
8. **占位行不剥夺行操作与行内反馈**(r146):占位(placeholder)只说明值未填。占位表单行仍必须渲染:① 行尾操作件(affordance 图标,候选池对 slice 与 symbol 同等对待——同一视觉图标在标注里可能是任一形态);② 行尾 pill 操作按钮(如 获取验证码);③ 值下方的行内反馈子值(如红色错误提示),右簇改纵向排布 [输入行, 子值行],子值与值列右对齐,标签与输入行顶对齐。
|
|
413
|
-
|
|
414
|
-
- scripts/validate_schema.py path/to/schema.json:校验单卡(JSON/结构/组件嵌套/已知类/属性样式键/itemValueFrom/v-show/data.json 一致性/componentId 唯一/指令/事件/action 形状)。加 --no-data 跳过 data.json。**加 `--topology` 可选触发拓扑合规性检查**(基于人力卡统计规则库 `references/handcrafted/patterns.json`,对比生成卡与人力卡范式偏离度,输出 INFO 级 hints 不阻断 validate)。`--json --topology` 输出机器可读 `topologyHints` 数组供 dev-server/CI 消费。
|
|
415
|
-
- scripts/check_topology.py path/to/schema.json:独立拓扑合规性检查器(纯建议层,永远不抛 error)。检查维度:骨架稀有度(父节点子序列在人力卡中支持度)/ slot 约定偏离 / 缺失必备 style itemKey / 变量命名非 ASCII / 文本绑定 $expr 比例偏离。`--quiet` 只输出摘要。
|
|
416
|
-
- scripts/validate_all_schemas.py src/cards:全量校验。
|
|
417
|
-
- scripts/derive_data_json.py path/to/schema.json --check / --overwrite:派生/检查 data.json。
|
|
418
|
-
- scripts/inventory_schemas.py src/cards --examples:盘点当前 DSL 面(组件类/属性/样式/指令/事件/action 频次 + 示例),同步新导出后先跑这个。
|
|
419
|
-
- scripts/scaffold_card.mjs --intent <blank|list|detail|form|dialog|tab|canvas-head> --id <卡id> --name <名称>:秒出合法最小骨架 + 自洽 data.json(提速核心,形状来自 lib/scaffold.mjs)。
|
|
420
|
-
- scripts/extract_handcrafted.py:从 src/cards 抽取人力卡拓扑/参数/变量规则,刷新 `references/handcrafted/patterns.json`(统计规则库)与 `examples_index.json`(示例库索引)。src/cards 增删卡后重跑即可。
|
|
421
|
-
- scripts/add_component.mjs --id <卡id> --parent <componentId> --className <Text|Row|...> [--text "文案"] [--click] [--set-prop key=value ...]:向容器插入合法最小组件,只增不改;`--set-prop`(可重复,值以 `$` 开头判为绑定)用于视觉闭环单点改属性,免去每轮全文重写 schema。
|
|
422
|
-
- scripts/autofix_schema.py <schema.json> [--check]:机械修复 itemValueFrom=1 缺 itemDefaultValue、重复 componentId、data.json 漂移,复校验并报告。
|
|
423
|
-
- scripts/build_card_index.mjs:重算 references/card_index.json(意图路由选近邻用)。
|
|
424
|
-
- **scripts/route_input.mjs <输入路径> [--json]**:建卡输入形态路由(Workflow 0 的机械判定器)。判 `meaxure-export`(index.html 内嵌 artboards + preview/ + assets/)/ `ui-bundle`(manifest.json,或 spec.json + card-N.png)/ `card-dir`(schema.json → Workflow B)/ `image`(单图 → Workflow A)/ `unknown`,输出判定证据 + 下一步命令。MeaXure 导出会比对 `UI/*/manifest.json` 的 `export` 字段判断是否已前处理(已处理则跳过管线、直接给存量产物路径),未处理则给出 `sketch-spec-to-card` 的 `parse_meaxure.py --draft` + `cluster_states.py --out` 两条命令。退出码 0=已路由 / 3=unknown / 1=用法或路径错误。
|
|
425
|
-
- **scripts/apply_opacity_pattern.mjs --id <卡id> [--check|--dry] [--json] [--node <cid>] [--container Row|Column]**:把透明度表达式节点机械改写成透明度切换固定范式(R57)——解析 `COND ? A : B` / 右嵌套三元为静态变体表,生成等宽高 + overflow:hidden 的容器、事件上移、互斥 v-show;`--check` 只报告(有则 exit 1,可进 CI)。不可解析的表达式 exit 2 提示手工改写。范式见 `recipes.md §17`。
|
|
426
|
-
- **scripts/expand_ir.mjs --ir <IR.json> --out src/cards/<卡id>/**:紧凑 IR → 合法 schema/data;自动从 IR 同目录 `slices/` 汇聚 schema 引用的静态切图到 `src/slices/`。详见 `references/ir-format.md`。
|
|
427
|
-
- **scripts/diff_card.mjs --id <卡id> [--baseline <path.json> | --against <otherId>] [--json] [--strict]**:卡片变更对比(铁律机械兜底)。默认基线 = git HEAD;输出删除/新增/修改的 componentId 与字段级 diff。整体替换 schema 后必跑一次,确认未涉及节点真保留。
|
|
428
|
-
- **scripts/lint_card.mjs --id <卡id> | --all [--json] [--strict]**:卡片健康度体检(≠ validate)。检查项:脚手架占位残留、未使用的 inputParams、Button 缺 click、Root 缺 background、Text 缺 font.color、Canvas 缺 onMeasured、eventKey 与组件类型不匹配等。
|
|
429
|
-
- **scripts/extract_subtree.mjs --id <卡id> --component-id <cid> [--name <片段名>] [--out <path>]**:从已导出卡抽取任意子树,生成可复用片段(recipe snippet)。输出含完整 subtree + 自动探测的 requiresInputParams(依赖键),让范式库可持续增长(不再只有 6 个硬编码配方)。详见 references/recipe_snippets/。
|
|
430
|
-
- **scripts/describe_card.mjs --id <卡id> [--json]**:卡片反向描述初稿生成器。自动产出元信息 / 组件树 ASCII / 数据来源 / 事件流四节,作为自然语言摘要的机器初稿;一句话定位与可改范围需人/AI 润色。模板见 references/card_to_summary.md。
|
|
431
|
-
- **scripts/preflight.mjs --spec <spec.json> --id <卡id>**:一键机械 Pre-flight(10 项自动拦截:元素计数/组件白名单/Image itemValueFrom/rect.height/切图文件名空格/Icon eventaction/百分比表达式/Divider vs Row/根样式完整性/空 itemId)。替代 AI 手动过 12 项 checklist。
|
|
432
|
-
- **scripts/check_magic_values.mjs**:魔法值门禁(L3)。扫描 v3 生成器源码,禁止 layout 魔法值(gap/padding/borderRadius/fontSize 裸数字),必须引用 lib/layout-tokens.mjs(T.gap/T.pad/T.radius/T.font/T.color)。有违规 exit 70 供 CI。改生成器后必跑。
|
|
433
|
-
- **scripts/check_fidelity.mjs --spec <spec.json> --schema <schema.json> [--card 1] [--json] [--font-tol 2] [--color-tol 24]**:保真度门禁(L4/fidelity)。元素级对齐断言——spec 每个文本元素应在 schema 中找到对应 Text(内容匹配),字号偏差 ≤ `--font-tol`、颜色 rgba 各通道差 ≤ `--color-tol`;缺失/超差即 exit 非 0。覆盖间距/颜色/字号这类前四层查不出的高频错误。`npm run check:fidelity` 接入 CI。
|
|
434
|
-
- **scripts/lib/layout-tokens.mjs**:布局 Token 表(L1)。GAP/PADDING/RADIUS/FONT/COLOR 语义化常量,v3 生成器统一引用;改值单点生效。**禁止在生成器里写裸魔法值**。
|
|
435
|
-
- **scripts/render_baseline.mjs [--snapshot|--diff] [--id <卡id>] [--threshold 0.01] [--json]**:渲染回归基线(离线独立渲染器,不依赖 dev server)。`--snapshot` 建立/刷新 `<宿主>/.card-baselines/<id>.png`(可用 `DSL_CARD_BASELINES_DIR` 覆盖);`--diff` 对比当前渲染与基线的像素差异(装 sharp 启用真实像素 diff,否则降级为字节/大小比较),差异超阈值时 exit 70 供 CI 识别。配合 §四层校验自洽说明使用。
|
|
436
|
-
- **scripts/render_card.mjs --id <卡id> [--width 375] [--out render.png] [--format json|png]**:单卡离线截图。复用 `vendor/preview/` 构建产物(`npm run build:skill-preview` 产出),纯 Node HTTP 托管 + 系统 Chrome CDP 截取 `.phone__screen`,截图后立即关闭,不占 5180/8787、不与本地开发服务冲突。视觉迭代多轮可用 `--keep-alive`,逐行输入 `{"id":"<卡id>","outFile":"<png>"}`,stdin EOF 后自动清理 Chrome。
|
|
437
|
-
- **scripts/render_diff.mjs --card <卡id> --design <设计图>**:并排视觉对比;省略 `--width` 时自动读取 `schema.view.width`,避免 343 卡被按 375 渲染后误判裁切。
|
|
438
|
-
- **MCP 脚手架工具(P5,见 mcp/,直接复用 lib/scaffold.mjs)**:`card_scaffold({intent,id,name,outBase,platform,force})` 建骨架、`card_add_component({id,parent,className,text,click})` 插组件并离线校验。与上面 CLI 同源,无需 dev server。
|
|
439
|
-
- **MCP 输入路由(见 mcp/,直接复用 scripts/route_input.mjs 的 `routeInput()`)**:`card_route_input({path})` 判建卡输入形态(`meaxure-export` / `ui-bundle` / `card-dir` / `image` / `unknown`),返回 `evidence` + `next` + `preprocess`,等价 CLI `--json`。`meaxure-export` 且 `preprocess.needed=true` 时,`next` 直接给出 sketch-spec-to-card 的两条前处理命令;已前处理过则给存量产物路径。离线,无需 dev server;`path` 支持工程根相对路径与 `~` 展开,路径不存在返回 `error:"input-not-found"`。
|
|
440
|
-
|
|
441
|
-
校验器不证明设计器里的运行时行为,风险交互仍需在平台里核对。
|
|
442
|
-
|
|
443
|
-
> **三层校验自洽**:validate(结构合法)→ lint(体验达标)→ diff(铁律保留)。三者互补不重叠——validate 是 CI 硬卡点;lint 是软提醒(脚手架生成卡默认会触发若干 info);diff 是"刚改完这张卡,确认没误删什么"的回看工具。三者底层都从同一份 lib/paths.{mjs,py} 解析路径,目录重构时无需同步多处。
|
|
444
|
-
>
|
|
445
|
-
> **第四层:渲染回归基线**(`render_baseline.mjs`)——每张导出卡在固定视口下存 PNG 基线,改完渲染器后 `--diff` 检测像素级视觉回归。基线存 `<宿主>/.card-baselines/`(gitignored),CI 单独存 artifact。已改为离线独立渲染器,无需 dev server、不占端口。
|
|
446
|
-
|
|
447
|
-
## 11. 参考路由(按需只读需要的)
|
|
448
|
-
|
|
449
|
-
- **references/rules.md**:**铁律集中陈述**(十三节:证据分级 / 不污染 DSL / DSL 契约 / 运行时作用域与 Input 回写 / 速查优先 / 验证三层自洽 / 视觉真相优先 / 远端同步前置 / 组件级硬约束 / 从脚手架起步 / 标注可信度分层 / 卡片目录命名 / **画板聚焦与卡片生成单位(多画板必须先选卡)**)。其他文档只引用,不再重复措辞。
|
|
450
|
-
- references/dsl_structure.md:顶层结构、数据模型、data.json、view 根、组件形状、插槽/作用域、样式系统完整 itemId 表、指令(v-show)、已知事实。
|
|
451
|
-
- references/component_specs.md:15 个可渲染组件的完整 JSON 骨架 + 属性 itemId 表 + styleState 默认 + 事件/插槽。
|
|
452
|
-
- references/expression_engine.md:$ 表达式引擎、evalExpr、itemValueFrom 0/1/2、itemDefaultValue、itemCondition 语法、作用域插槽 $$/_index、v-show、Input 回写、表达式片段库(金额/尾号/slice/三元)。
|
|
453
|
-
- references/amount_formatting.md:**金额处理规范**(生成器默认口径)。设计稿出现「金额 / 余额 / 还款额 / ¥」等字样 → 对应 inputParams 默认 `type:"number"` + 显示用表达式做千分号;含 canonical 表达式库(带/不带 `¥` 前缀、列表项 fallback、反向解析回数字)、与上游 `_fmt` 预格式化的取舍、data.json 一致性;§7 给「句中带金额」混排串拼接范式。中文+数字混排串的语义提取铁律见 `references/rules.md §十四`。权威范例 = multiMonthTransitionList(export-proven)。
|
|
454
|
-
- references/event_patterns.md:eventactions 形状、eventKey/actionType、this.state/data/setData、addEventListener/postMessage、globalSet、JSAPI 调用范式、生成清单。
|
|
455
|
-
- **references/field_naming.md**:**字段命名规范(双层机制)**。脚本层:标签词典 `field_name_dict.json`(领域通用词表)+ 值格式角色兜底,永不出现 obj_N/amount_0 序号名;智能体层:生成后按 UI 标签实际含义复核/优化 key,同步 data.json 与绑定表达式。含命名风格、禁止项、词典词表、增补方法、复核清单。**数组统计字段(枚举统计行)命名见 §3.1**。v3 直组装范式的命名细则见 `spec_to_schema_patterns.md §2.3`。
|
|
456
|
-
- references/recipes.md:Canvas 标题头、alertCard 弹窗 + 同名 Dialog 表、列表展开收起、globalSet 子→父、金额格式化、Tab↔标题头 billMode、**纯 Tab 切换(activeTab + setData + v-show,§7)**、**背景图承载复杂背景 / 状态相关视觉(backgroundImage,§8)**、**手风琴分组折叠(icon 按钮 + 每组 hide 布尔 + globalSet 深路径翻转 + 内容 v-show,§9)**、**Canvas 甜甜圈/环形比例图(onMeasured 双弧回描 + onReady 算 ratio,§10)**、**角标/角标签(AbsoluteLayout 叠加小标 + align 选角 + 胶囊样式,§11)**、**标题+下划线重叠(AbsoluteLayout 绝对定位,禁止负 marginTop,见 recipe_snippets/title-underline-overlay.json)**、**Canvas 评分仪表盘(弧形进度环 + 真实字体中心分数,§14)**、**Canvas 五维雷达图(渐变填充 + 网格,§15)**、**维度标签列同行式/堆叠式两范式(§16)**、**透明度切换固定范式(静态变体 ×N + 等宽高 overflow:hidden 容器 + 事件上移 + 互斥 v-show,§17,铁律 R57)**,各含 export-proven 代码。
|
|
457
|
-
- references/previewer_contract.md:**预览器行为契约**(排雷必读)。容器默认 width:100% / Column 默认 justifyContent:center / 组件默认 overflow:hidden / AbsoluteLayout 不支持 position 组(用 align+margin)/ Canvas ctx 白名单(禁 save/scale/transform/drawImage)/ fontWeight 枚举 400-500-600 / font 组无 fontFamily(特殊字体宽度匹配法或走 Canvas)/ 预览默认 line-height:1.5 / 间距微调防级联 / 量化证据优先于肉眼。
|
|
458
|
-
- **references/spec_to_schema_patterns.md**:v3 直组装范式全集。**§19 枚举统计行(Enum-Stat Strip)**:`类型标签+数字` 枚举统计(`标签A 5 · 标签B 2 · 标签C 1 · 标签D 4`)→ 结构化数组字段 + map/join 渲染表达式,纯结构信号识别,泛用于未读分类/状态计数/分类金额/占比分布等任何枚举统计场景。**§10 动态参数提取**:姓名/卡号等运行期数据必须绑定。
|
|
459
|
-
- references/image_to_card.md:图片→schema 管线(dsl_json 契约)、编辑器 add/edit 语义、prompt 配方、组成清单方法论。
|
|
460
|
-
- references/slices_convention.md:**切图资产约定(issue-slices 系列)**。扁平唯一落点 `src/slices/`、schema 引用格式 `/slices/<扁平名>`、仅拷贝被引用切图(全量回归先清空再重建)、Vite 与 cardbuddy 均挂载 `/slices/*` 本地预览、排除 `99.切图/*` 导出目录切图、元素名↔导出文件名归一化匹配、常见错误与校验清单。
|
|
461
|
-
- **references/message-center-pattern.md**:消息中心/通知列表类卡生成范式(2026-08-17 沉淀)。canonical 拓扑 + 字段命名(unreadTotal/unreadBreakdown/messageList)+ 列表项模板(红点 Divider 模拟 + 双行文本 + 箭头)+ 关键纪律(Icon glyph 有效名/padding 多值拆 4 边/slots[0].components 形式)+ 端到端构造脚本范式。**分类统计副标题(`标签A 5 · 标签B 2 · 标签C 1 · 标签D 4`)已升级为结构化数组绑定(§3),是枚举统计行范式的权威范例**。
|
|
462
|
-
- references/platform_jsapi.md:JSAPI 完整目录(alertCard/closeAlertCard/alertDialog/showToast/showPicker/showDatePicker/showLoadingEx/startRouter 等)签名 + 49 卡实测频次。
|
|
463
|
-
- references/quickref.md:**一页纸速查**(常用组件最小骨架 + 表达式 + 事件范式 + data.json 铁律 + 快路径命令 + 范式片段索引)。常规任务只看它,不要加载下面全部 references。
|
|
464
|
-
- references/recipe_snippets/:预校验可复制的范式块(list-expand-collapse / alertCard-pair / globalSet / money-format / canvas-title-head / tab-billMode / accordion-group-toggle / canvas-donut / absolute-badge / progress-bar / **title-underline-overlay(标题+下划线重叠用 AbsoluteLayout,禁止负 margin)** / **canvas-gauge-score(评分仪表盘)** / **canvas-radar(雷达图)** / **label-col-modes(维度标签列两范式 + pill/tag 参数)** / **opacity-switch(透明度切换固定范式,R57)**),各含 `apply` 字段。新范式可用 `extract_subtree.mjs` 从已导出卡抽取,无需手抄。
|
|
465
|
-
- references/card_index.json:`build_card_index.mjs` 产出的卡片索引(每张卡 `components`/`recipes`/`tags`),意图路由选近邻用,不扫源文件。
|
|
466
|
-
- **references/component_rules.md**:组件级硬约束速查表(Icon 必须 emits:click 否则双触发、Input events:[]、ListLayout/GridLayout slotScope:true、Canvas 必须 onMeasured、Button.disabled 字符串 "false" 也为真、v-show 放置位置等)。一次性看完,避免遗漏。
|
|
467
|
-
- **references/image_diff.md**:视觉验证清单(七维度:布局/层级/文案/留白/配色/字号/交互元素)。Workflow A 第 6 步 `card_screenshot` 后按此逐项核对,把"基本一致"升级为有结构的逐项核查。
|
|
468
|
-
- **references/generation_pitfalls.md**:**生成避坑清单**(沉淀自 gen-card-test 真实生成)。集中讲透:itemValueFrom 必填(运行时静默丢弃根因)、style itemId 权威来源与 flexDirection=006 陷阱、图片/背景资源解析、**缺素材时用占位图**(Image 空 value→自动 default-image 占位图、Icon 缺 glyph 改占位 Image、复杂背景效果先占位)、布局陷阱(Column 100% 宽换行 / 空 Row 不渲染→Divider / alignItems)、Playwright 视觉真相验证配方、生成—校验—修复闭环。常规生成任务先扫一遍。
|
|
469
|
-
- **references/ui_fidelity_rules.md**:**UI 还原度规则**(沉淀自 r060-r083 批量训练 20+ 轮)。聚焦「渲染了但不像设计稿」的布局/尺寸/对齐问题:①Text 高度与 maxLine 协调(多行不设高度,单行 maxLine=1);②Text 宽度由内容决定(控制宽度需包裹容器);③表单行布局范式(标签固定宽度+右簇 flex 撑满);④Flexbox 坐标累积偏移原理与校正;⑤高度由内容撑起不写死;⑥width:100% 使用纪律;⑦位置还原优先级(存在→尺寸→中心→IoU);⑧标注与图像交叉验证(模型多模态能力);⑨背景不透明铁律与纯色兜底。**生成卡片前必读——直接影响 UI 还原度评分。**
|
|
470
|
-
- **references/card_to_summary.md**:卡片反向描述模板(元信息/组件树 ASCII/数据来源/事件流/可改范围)。给非设计人员解释卡片、写文档、AI 上下文压缩时套用;机器初稿用 `describe_card.mjs` 生成。
|
|
284
|
+
---
|
|
285
|
+
### button text consumed again as list title caused duplicate gh(r018n 训练回灌)
|
|
286
|
+
> lesson: `LESSON-20260825-037` status: `promoted`
|
|
471
287
|
|
|
472
|
-
|
|
288
|
+
源文本单一消费:按钮文案必须从列表标题候选中互斥排除;列表标题必须绑定完整业务容器,而不是按钮壳。
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
### fixed root height clipped variable-length content(r018n 训练回灌)
|
|
293
|
+
> lesson: `LESSON-20260825-038` status: `promoted`
|
|
294
|
+
|
|
295
|
+
Root/普通容器高度必须 auto,由子内容、gap 和标注 padding 撑开;只有叶子控件可读标注高度。
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
### panel value and repeated right affordance leaked into other (r039n 训练回灌)
|
|
300
|
+
> lesson: `LESSON-20260826-044` status: `promoted`
|
|
301
|
+
|
|
302
|
+
源文本单一消费扩展到副金额:面板 label/value 必须从列表标题候选互斥排除;同一右缘、同尺寸、等距重复的小控件由列表或重复行模板唯一消费,不得再作为孤立媒体块渲染。
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
### semantic gaps were double-counted and list spacing overflowe(r039n 训练回灌)
|
|
307
|
+
> lesson: `LESSON-20260826-045` status: `promoted`
|
|
308
|
+
|
|
309
|
+
列表标题、列表项和查看更多必须注册语义边界;相邻块间距只计一次。列表行内边距由标注行高减内容高推导,ListLayout 行间距显式归零,容器高度继续由内容撑开。
|
|
473
310
|
|
|
474
|
-
- 生成避坑清单(itemValueFrom 必填、style itemId 权威来源、图片解析、布局陷阱、Playwright 视觉验证、**进度条必须数据驱动**)集中见 `references/generation_pitfalls.md`(§8 专讲进度条:绑定 ≤1 比率变量映射宽度,禁止静态写死百分比),常规生成任务先扫一遍。
|
|
475
|
-
- 不要仅凭 palette/源码注册就声称组件或 action 可用;生成前要求有导出 JSON 形状。6 个编辑器专属类预览不渲染。
|
|
476
|
-
- actionType 已验证值:customAction/startRouter/closeAlertCard/sendAiChatMessage。alertCard/showPicker/showToast 等是 customAction 里的 JSAPI 调用,不是 actionType。
|
|
477
|
-
- 优先复用 src/cards/*/schema.json 结构;按模式选近邻参考(见 Workflow A step 3)。
|
|
478
|
-
- 改已有 schema 时除非真新增组件,否则保持 componentId 稳定。
|
|
479
|
-
- 不要把导出里的未知字段"归一化"掉;保留并告警,直到平台语义明确。
|
|
480
|
-
- data.json 必须从 dictionary.inputParams[].defaultValue 逐字节可派生;改一处必改另一处。
|
|
481
|
-
- itemValueFrom:"1" 的属性**必须**带 itemDefaultValue(预览器 undefined 兜底,否则渲染空)。
|
|
482
|
-
- Canvas onMeasured 的 event.canvas 是**设计稿坐标系**包装对象(宽度/2dctx 坐标已按 scale 换算),绘图用逻辑设计 px,不要乘 devicePixelRatio。
|