@topmindspace/tms-skills 0.1.2 → 0.1.4

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.
Files changed (34) hide show
  1. package/CHANGELOG.md +46 -1
  2. package/README.md +14 -4
  3. package/bin/tms-skills.js +7 -2
  4. package/package.json +2 -2
  5. package/top-ppt-html/README.md +40 -27
  6. package/top-ppt-html/SKILL.md +20 -16
  7. package/top-ppt-html/agents/openai.yaml +5 -0
  8. package/top-ppt-html/assets/pptx-export.js +69 -25
  9. package/top-ppt-html/assets/style-gallery.html +1 -1
  10. package/top-ppt-html/assets/templates/architecture.html +69 -25
  11. package/top-ppt-html/assets/templates/presentation.html +69 -25
  12. package/top-ppt-html/assets/templates/research.html +69 -25
  13. package/top-ppt-html/evals/trigger-queries.json +181 -0
  14. package/top-ppt-html/package.json +4 -3
  15. package/top-ppt-html/references/chart-decision-tree.md +42 -0
  16. package/top-ppt-html/references/default-surface.md +3 -2
  17. package/top-ppt-html/references/illustration-layout.md +39 -0
  18. package/top-ppt-html/references/modes.md +1 -1
  19. package/top-ppt-html/references/outline-design.md +24 -0
  20. package/top-ppt-html/references/page-type-matrix.md +35 -0
  21. package/top-ppt-html/references/playbook.md +28 -89
  22. package/top-ppt-html/references/pptx-export.md +1 -1
  23. package/top-ppt-html/references/presentation-craft.md +11 -2
  24. package/top-ppt-html/references/tech-design.md +6 -0
  25. package/top-ppt-html/scripts/audit_docs.py +1 -1
  26. package/top-ppt-html/scripts/audit_skill.py +43 -4
  27. package/top-ppt-html/scripts/build_pptx.js +24 -10
  28. package/top-ppt-html/scripts/check_triggers.py +153 -0
  29. package/top-ppt-html/scripts/negative_tests.py +10 -0
  30. package/top-ppt-html/scripts/package_skill.py +17 -1
  31. package/top-ppt-html/scripts/quality_gate.py +30 -19
  32. package/top-ppt-html/scripts/test_feedback_gates.py +180 -0
  33. package/top-ppt-html/scripts/validate_pptx.py +157 -0
  34. package/top-ppt-html/scripts/validate_report.py +27 -0
@@ -2148,7 +2148,7 @@ var STYLE_DATA_COLORS = {"business-blue":["1a73e8","3526bb","21a199","b77148","9
2148
2148
  var STYLE_DATA_COLORS_DARK = {"business-blue":["8ab4f8","7966e0","88e7e5","d4ad91","cbce83"],"apple-mono":["f5f5f7","2997ff","2dd4bf","ff9f0a","bf5af2"],"mckinsey":["7fb2e5","6f6bdb","8ce3d8","d1a694","cbc586"],"brand-red":["ff5a66","e09e66","e788cb","91d4c2","83b4ce"],"warm-sand":["d9b36a","c2d571","df9391","97b5ce","8e89c7"],"deep-teal":["4fc3b0","7aaecd","97d8a4","c99cac","c29c8f"],"graphite-dark":["4da3ff","6c66e0","88e7dc","d4a691","cec983"],"indigo-violet":["a5a4f0","a967e0","89c3e7","d3c792","aece83"],"spectrum":["8ba0f8","9066e0","88d6e7","d4ba91","bdce83"]};
2149
2149
  var GRID = {"columns":12,"gutter":0.16,"colW":0.8644,"x":[0.6,1.6244,2.6488,3.6732,4.6976,5.722,6.7464,7.7708,8.7952,9.8196,10.844,11.8684,12.733],"y":[2.35,3.27,4.19,5.11,6.03,6.9],"safe":{"top":0.4,"bottom":0.4,"left":0.6,"right":0.6}};
2150
2150
  var TYPO = {"levels":[{"id":"C0","name":"封面/章节幕标题","role":"coverTitle","usage":"封面主标题、章节幕标题"},{"id":"T1","name":"页码/章节徽章","role":"caption","usage":"页码徽章、章节编号"},{"id":"T2","name":"页面主标题/结论标题","role":"h1","usage":"每页顶部结论句(research 行动标题)"},{"id":"T3","name":"副标题/语境说明","role":"lead","usage":"主标题下方导语"},{"id":"T4","name":"模块标题/图表标题","role":"h2","usage":"卡片标题、图表标题、面板标题"},{"id":"T5","name":"证据编号/轻量标签","role":"micro","usage":"Exhibit 编号、状态标签"},{"id":"T6","name":"证据块标题/小节标题","role":"h2","usage":"分栏小标题、证据块标题"},{"id":"T7","name":"正文解释段落","role":"body","usage":"证据解释、管理解读正文、表格正文"},{"id":"T8","name":"结论条文字","role":"body","usage":"so-what 结论条、核心结论框"},{"id":"T9","name":"SO WHAT 标签","role":"caption","usage":"so-what 标签行"},{"id":"T10","name":"SO WHAT 正文/业务含义","role":"body","usage":"so-what 正文、行动含义、表格行动项"},{"id":"T11","name":"图表轴/图例/刻度/微标签","role":"micro","usage":"坐标轴、图例、刻度、单位(禁用于表格正文与完整短句)"},{"id":"T12","name":"图表数据标签","role":"caption","usage":"折线点值、柱形标签、百分比标注"},{"id":"T13","name":"关键 KPI 大数字","role":"h1","usage":"KPI 大数字、hero 数值"},{"id":"T14","name":"注释/口径/来源/页脚","role":"micro","usage":"footnote、来源行、页脚、小页码"}],"tableSemanticRule":{"body":["T7","T10"],"microAllowed":["T11"],"microForbiddenFor":["表格正文","行动项","风险项","解释句","建议句","长项目符号","完整短句"]}};
2151
- var CONT = {"pad":{"card":0.18,"panel":0.2,"cell":0.08,"band":0.16,"soWhat":0.16,"kpi":0.18,"chart":0.1,"head":0.05,"footer":0.05,"node":0.06},"minPad":0.06,"textMetrics":{"lineFactor":1.45,"emAsciiRatio":0.52},"overflowRule":"溢出处置优先级:① 优化内容(列表化/精炼/合并/拆页/换组合版式)→ ② 调整容器尺寸与行宽 → ③ 有限度缩小字号(见 fontShrink)→ ④ 仍装不下则拆页。禁止无限缩字号硬塞,也禁止把「精简」当第一手段砍掉决策必需信息。","fontShrink":{"ladder":[15,14,13.5,13,12.5,12,11.5,11,10.5,10,9.5,9,8.5],"maxShrinkSteps":4,"floorPt":{"presentation":10,"research":9,"architecture":10},"preferContentFirst":true,"warnBelow":9.5},"continuousTextRule":"语义连续的一句话 / so-what 主句 / 结论句 / 表格单元格正文不得拆成多个独立文本框(避免异常空格、断句、基线漂移);局部加粗高亮必须用同一文本框内富文本。"};
2151
+ var CONT = {"pad":{"card":0.18,"panel":0.2,"cell":0.08,"band":0.16,"soWhat":0.16,"kpi":0.18,"chart":0.1,"head":0.05,"footer":0.05,"node":0.06},"minPad":0.06,"textMetrics":{"lineFactor":1.45,"emAsciiRatio":0.52},"overflowRule":"溢出处置优先级(禁静默截断):① 重构承载(列表/卡片/表/图/组合版式)→ ② 拆页/分章(议程→主张→证据卡→明细;01a/01b;信息须完整)→ ③ 换布局形态(V1–V4/多列/卡栅格)→ ④ 有限 fontShrink(阶梯内、模式 floor 以上、最多 4 档)→ ⑤ 禁止:静默截断、砍 so-what/证据/口径、为审美稀疏删决策必需信息。单页字数预算是预警不是删字许可证。","fontShrink":{"ladder":[15,14,13.5,13,12.5,12,11.5,11,10.5,10,9.5,9,8.5],"maxShrinkSteps":4,"floorPt":{"presentation":10,"research":9,"architecture":10},"preferContentFirst":true,"warnBelow":9.5},"continuousTextRule":"语义连续的一句话 / so-what 主句 / 结论句 / 表格单元格正文不得拆成多个独立文本框(避免异常空格、断句、基线漂移);局部加粗高亮必须用同一文本框内富文本。"};
2152
2152
  var REG = {"bar":{"html":"svg-bars","pptx":"native","nativeType":"bar","dataTable":"notes","min":{"vbHeightMin":160}},"hbar":{"html":"svg-hbars","pptx":"native","nativeType":"bar","dataTable":"notes","min":{"vbHeightMin":100}},"stack":{"html":"svg-stack","pptx":"native","nativeType":"bar","dataTable":"notes","min":{"vbHeightMin":160},"nativeOpt":{"barGrouping":"stacked"}},"stackline":{"html":"svg-stackline","pptx":"native","nativeType":"bar","dataTable":"notes","min":{"vbHeightMin":40},"nativeOpt":{"barGrouping":"percentStacked"}},"line":{"html":"svg-line","pptx":"native","nativeType":"line","dataTable":"notes","min":{"vbHeightMin":160}},"dualline":{"html":"svg-dualline","pptx":"native","nativeType":"line","dataTable":"notes","min":{"vbHeightMin":160}},"area":{"html":"svg-area","pptx":"native","nativeType":"area","dataTable":"notes","min":{"vbHeightMin":160}},"donut":{"html":"svg-donut","pptx":"native","nativeType":"doughnut","dataTable":"notes","min":{"pxWidthMin":140}},"multidonut":{"html":"svg-mdonut","pptx":"native","nativeType":"doughnut","dataTable":"notes","min":{"pxWidthMin":140}},"pie":{"html":"svg-pie","pptx":"native","nativeType":"pie","dataTable":"notes","min":{"pxWidthMin":140}},"radar":{"html":"svg-radar","pptx":"native","nativeType":"radar","dataTable":"notes","min":{"pxWidthMin":220}},"scatter":{"html":"svg-scatter","pptx":"native","nativeType":"scatter","dataTable":"notes","min":{"vbHeightMin":180}},"bubble":{"html":"svg-bubble","pptx":"native","nativeType":"bubble","dataTable":"notes","min":{"vbHeightMin":180}},"waterfall":{"html":"svg-wf","pptx":"native","nativeType":"bar","dataTable":"notes","min":{"vbHeightMin":170},"nativeTrick":"stacked+hiddenBase+connector"},"gauge":{"html":"svg-gauge","pptx":"native","nativeType":"doughnut","dataTable":"notes","min":{"pxWidthMin":180},"nativeTrick":"doughnut+firstSliceAng+hiddenRemainder"},"pareto":{"html":"svg-pareto","pptx":"native","nativeType":"bar","dataTable":"notes","min":{"vbHeightMin":180},"nativeTrick":"multiType+bar+line"},"gantt":{"html":"svg-gantt","pptx":"shape","dataTable":"notes","min":{"vbHeightMin":130},"path":{"forbidPresetShapes":true}},"vsbar":{"html":"svg-vsbar","pptx":"shape","dataTable":"notes","min":{"vbHeightMin":100},"path":{"forbidPresetShapes":true}},"progress":{"html":"svg-progress","pptx":"shape","dataTable":"notes","min":{"vbHeightMin":100},"path":{"forbidPresetShapes":true}},"sparkline":{"html":"svg-spark","pptx":"shape","dataTable":"off","min":{"vbHeightMin":20},"path":{"forbidPresetShapes":true}},"funnel":{"html":"svg-funnel","pptx":"shape","dataTable":"notes","min":{"vbHeightMin":160},"path":{"minSamplePoints":8,"forbidPresetShapes":true}},"treemap":{"html":"svg-treemap","pptx":"shape","dataTable":"appendix","min":{"vbHeightMin":170},"path":{"forbidPresetShapes":true}},"marimekko":{"html":"svg-marimekko","pptx":"shape","dataTable":"appendix","min":{"vbHeightMin":160},"path":{"forbidPresetShapes":true}},"boxplot":{"html":"svg-boxplot","pptx":"shape","dataTable":"appendix","min":{"vbHeightMin":180},"path":{"forbidPresetShapes":true}},"network":{"html":"svg-network","pptx":"shape","dataTable":"appendix","min":{"vbHeightMin":200},"path":{"forbidPresetShapes":true}},"sankey":{"html":"svg-sankey","pptx":"shape","dataTable":"appendix","min":{"vbHeightMin":200},"path":{"minSamplePoints":16,"trackBothEdges":true,"forbidPresetShapes":true}},"streamgraph":{"html":"svg-stream","pptx":"shape","dataTable":"appendix","min":{"vbHeightMin":160},"path":{"minSamplePoints":24,"trackBothEdges":true,"forbidPresetShapes":true}},"slope":{"html":"svg-slope","pptx":"shape","dataTable":"notes","min":{"vbHeightMin":180},"path":{"forbidPresetShapes":true}},"dumbbell":{"html":"svg-dumbbell","pptx":"shape","dataTable":"notes","min":{"vbHeightMin":160},"path":{"forbidPresetShapes":true}},"lollipop":{"html":"svg-lollipop","pptx":"shape","dataTable":"notes","min":{"vbHeightMin":140},"path":{"forbidPresetShapes":true}},"dotplot":{"html":"svg-dotplot","pptx":"shape","dataTable":"notes","min":{"vbHeightMin":120},"path":{"forbidPresetShapes":true}},"bulletchart":{"html":"svg-bullet","pptx":"shape","dataTable":"notes","min":{"vbHeightMin":140},"path":{"forbidPresetShapes":true}},"waffle":{"html":"svg-waffle","pptx":"shape","dataTable":"notes","min":{"vbHeightMin":160},"path":{"forbidPresetShapes":true}},"radialbar":{"html":"svg-radialbar","pptx":"shape","dataTable":"notes","min":{"pxWidthMin":200},"path":{"minSamplePoints":16,"forbidPresetShapes":true}},"rose":{"html":"svg-rose","pptx":"shape","dataTable":"notes","min":{"pxWidthMin":180},"path":{"minSamplePoints":16,"forbidPresetShapes":true}},"candlestick":{"html":"svg-candle","pptx":"shape","dataTable":"appendix","min":{"vbHeightMin":180},"path":{"forbidPresetShapes":true}}};
2153
2153
  var DEEP = {"triggers":["高保真","1:1","一比一","精确还原","按图还原","正式交付","不能偏移","像素级","严格对照","逐页验收"],"complexCharts":["sankey","streamgraph","treemap","marimekko","boxplot","network","rose","radialbar","candlestick","funnel"],"checks":{"anchors":true,"containerOverflow":true,"renderCompare":true,"manifest":true},"renderCompare":{"engine":"soffice","fallback":"powerpoint-com","skipIfMissing":true,"dpi":96}};
2154
2154
  var IMG = {"layouts":["full","half","bleed","grid","compare","wall"],"multiLayouts":["grid","compare","wall"],"fitEnum":["cover","contain"],"fitDefault":"cover","formats":["png","jpeg","jpg","webp","svg"],"ratioDefault":{"full":"3:1","half":"4:3","bleed":"21:9","grid":"4:3","compare":"4:3","wall":"1:1"},"ratioCssClass":{"full":"media--r3-1","half":"media--r4-3","bleed":"media--r21-9","grid":"media--r4-3","compare":"media--r4-3","wall":"media--r1-1"},"recommendedSizePx":{"full":"2400×800","half":"1400×1050","bleed":"2560×1100","grid":"900×675","compare":"1400×1050","wall":"480×480"},"maxInlineBytes":1572864,"maxTotalInlineBytes":8388608,"maxPerPage":6,"placeholderLabel":"配图占位","placeholderHintPrefix":"建议 ","placeholderHintSuffix":"px","zeroExternal":true,"qualityRule":"位图优先提供 ≥2× 显示尺寸;截图用 16:9 或 4:3 锁定比例;数据图不要用截图(应用内联 SVG 图表,可随主题变色)。"};
@@ -2345,6 +2345,16 @@ function modeFloorPtA(mode) {
2345
2345
  var m = String(mode || 'presentation');
2346
2346
  return (floors[m] != null) ? floors[m] : 10;
2347
2347
  }
2348
+ function snapFont(pt, ladder, floor) {
2349
+ var lad = (ladder || FONT_LADDER).filter(function (v) { return v >= (floor == null ? 0 : floor); });
2350
+ if (!lad.length) return floor == null ? pt : Math.max(floor, pt);
2351
+ var best = lad[0], bd = Math.abs(lad[0] - pt);
2352
+ for (var i = 1; i < lad.length; i++) {
2353
+ var d = Math.abs(lad[i] - pt);
2354
+ if (d < bd) { bd = d; best = lad[i]; }
2355
+ }
2356
+ return best;
2357
+ }
2348
2358
  function fitFont(items, widthIn, availIn, opts) {
2349
2359
  opts = opts || {};
2350
2360
  var max = (opts.max == null) ? 99 : opts.max, lf = opts.lineFactor || 1.45;
@@ -2689,7 +2699,7 @@ function imageLayoutShapes(sh, S, layout, img, items, points, isPh, fit, y0, y1)
2689
2699
  sh.push(shape('rect', rxI, lyI + rowHI / 2 - 0.06, 0.12, 0.12, S.accent));
2690
2700
  sh.push(txSp(rxI + 0.26, lyI, rwI - 0.3, rowHI - 0.04,
2691
2701
  [[{ t: (pt[0] || '') + ' ', sz: fzI, b: 1, col: S.ink, font: S.font },
2692
- { t: pt[1] || '', sz: fzI - 1, col: S.body, font: S.font }]], { anchor: 't' }));
2702
+ { t: pt[1] || '', sz: snapFont(fzI - 1), col: S.body, font: S.font }]], { anchor: 't' }));
2693
2703
  });
2694
2704
  capY = iy + Math.max(ihh, ih * 0.5);
2695
2705
  } else if (layout === 'bleed') {
@@ -2738,24 +2748,55 @@ function hbarRows(sh, ec, S, y0, y1, dcols, x0, w) {
2738
2748
  }
2739
2749
  /* 竖柱 / 堆叠柱 */
2740
2750
  function vbarShapes(sh, ec, S, x, y, w, h, dcols) {
2741
- var labels = ec.labels || [], values = ec.values || [];
2751
+ /* Multi-series aware (mirrors lineShapes): ec.series[{name,values}] or single ec.values. */
2752
+ var labels = ec.labels || [];
2753
+ var series = (ec.series && ec.series.length)
2754
+ ? ec.series
2755
+ : [{ name: '数值', values: ec.values || [] }];
2742
2756
  var nb = Math.max(1, labels.length);
2757
+ var ns = Math.max(1, series.length);
2743
2758
  var baseY = y + h, plotW = w, step = plotW / nb;
2744
- var bw = Math.min(1.1, step * 0.55);
2745
- var vmax = ec.max || Math.max.apply(null, values.concat([1]));
2746
- var top = values.length ? Math.max.apply(null, values) : 0;
2759
+ var cluster = Math.min(1.1, step * (ns > 1 ? 0.78 : 0.55));
2760
+ var bw = cluster / ns;
2761
+ var all = [];
2762
+ series.forEach(function (se) {
2763
+ (se.values || []).forEach(function (v) { all.push(Number(v) || 0); });
2764
+ });
2765
+ var vmax = ec.max || Math.max.apply(null, all.concat([1]));
2766
+ var top = all.length ? Math.max.apply(null, all) : 0;
2747
2767
  sh.push(shape('rect', x, baseY, plotW, 0.02, S.line));
2748
- values.forEach(function (v, i) {
2749
- var hh = Math.max(0.05, v / vmax * (h - 0.5));
2750
- var bx = x + i * step + (step - bw) / 2;
2751
- var hot = v === top;
2752
- var dc = dcols ? dcols[i % 5] : null;
2753
- sh.push(shape('roundRect', bx, baseY - hh, bw, hh, dc || (hot ? S.accent : S.faint), { adj: 6000 }));
2754
- sh.push(txSp(bx - 0.3, baseY - hh - 0.4, bw + 0.6, 0.32,
2755
- [[{ t: valText(v, ec.unit), sz: 12.5, b: 1, col: hot ? S.accent : S.body, font: S.font }]], { align: 'ctr' }));
2756
- sh.push(txSp(bx - 0.3, baseY + 0.08, bw + 0.6, 0.32,
2757
- [[{ t: labels[i], sz: 10.5, col: S.faint, font: S.font }]], { align: 'ctr' }));
2768
+ series.forEach(function (se, si) {
2769
+ var vals = se.values || [];
2770
+ var col = dcols ? dcols[si % 5] : (si === 0 ? S.accent : S.faint);
2771
+ vals.forEach(function (v, i) {
2772
+ var num = Number(v) || 0;
2773
+ var hh = Math.max(0.05, num / vmax * (h - 0.5));
2774
+ var bx = x + i * step + (step - cluster) / 2 + si * bw;
2775
+ var hot = ns === 1 && num === top;
2776
+ sh.push(shape('roundRect', bx, baseY - hh, Math.max(0.04, bw * 0.92), hh,
2777
+ hot ? (dcols ? dcols[i % 5] : S.accent) : col, { adj: 6000 }));
2778
+ if (ns === 1) {
2779
+ sh.push(txSp(bx - 0.3, baseY - hh - 0.4, bw + 0.6, 0.32,
2780
+ [[{ t: valText(num, ec.unit), sz: 12.5, b: 1, col: hot ? S.accent : S.body, font: S.font }]], { align: 'ctr' }));
2781
+ }
2782
+ });
2758
2783
  });
2784
+ labels.forEach(function (lb, i) {
2785
+ var lx = x + i * step;
2786
+ sh.push(txSp(lx, baseY + 0.08, step, 0.32,
2787
+ [[{ t: lb, sz: 10.5, col: S.faint, font: S.font }]], { align: 'ctr' }));
2788
+ });
2789
+ /* Multi-series legend along top of plot (keeps category labels; avoids blank chart). */
2790
+ if (ns > 1) {
2791
+ var lx2 = x;
2792
+ series.forEach(function (se, si) {
2793
+ var col2 = dcols ? dcols[si % 5] : (si === 0 ? S.accent : S.faint);
2794
+ sh.push(shape('rect', lx2, y, 0.12, 0.12, col2));
2795
+ sh.push(txSp(lx2 + 0.16, y - 0.02, 1.4, 0.24,
2796
+ [[{ t: String(se.name || ('系列' + (si + 1))), sz: 10, col: S.body, font: S.font }]]));
2797
+ lx2 += 1.6;
2798
+ });
2799
+ }
2759
2800
  }
2760
2801
  /* 折线 / 双折线 / 面积 */
2761
2802
  function lineShapes(sh, ec, S, x, y, w, h, dcols) {
@@ -3162,8 +3203,11 @@ function infoApprox(sh, sec, S, y0, y1) {
3162
3203
  totals.push(tt);
3163
3204
  }
3164
3205
  var maxTot = Math.max.apply(null, totals.concat([1]));
3165
- var plotH3 = P.y1 - P.y0;
3166
- var cyMid = (P.y0 + P.y1) / 2;
3206
+ /* Reserve legend INSIDE the plot box so 6-series pages do not crush the annotation band. */
3207
+ var legH = Math.min(1.2, Math.max(0.28, series.length * 0.22 + 0.08));
3208
+ var plotBottom = P.y1 - legH;
3209
+ var plotH3 = Math.max(0.6, plotBottom - P.y0);
3210
+ var cyMid = P.y0 + plotH3 / 2;
3167
3211
  var base = totals.map(function (tv) { return cyMid - tv / maxTot * plotH3 / 2; });
3168
3212
  series.forEach(function (se, si) {
3169
3213
  var upper = base.map(function (bv, i3) { return bv + (values[si][i3] || 0) / maxTot * plotH3 / 2; });
@@ -3173,12 +3217,12 @@ function infoApprox(sh, sec, S, y0, y1) {
3173
3217
  sh.push(shape('rect', MX + i4 * stepX, (base[i4] + base[i4 + 1]) / 2, stepX, hgt, palette[si % palette.length]));
3174
3218
  }
3175
3219
  base = upper;
3176
- sh.push(shape('rect', MX, P.y1 + 0.06 + si * 0.26, 0.12, 0.12, palette[si % palette.length]));
3177
- sh.push(txSp(MX + 0.16, P.y1 + si * 0.26, 1.5, 0.26,
3220
+ sh.push(shape('rect', MX, plotBottom + 0.04 + si * 0.2, 0.12, 0.12, palette[si % palette.length]));
3221
+ sh.push(txSp(MX + 0.16, plotBottom + 0.02 + si * 0.2, 1.5, 0.2,
3178
3222
  [[{ t: String(se.name || ('系列' + (si + 1))), sz: 10, col: S.body, font: S.font }]], { anchor: 'ctr' }));
3179
3223
  });
3180
3224
  labels.forEach(function (lb, i5) {
3181
- sh.push(txSp(MX + (nPts > 1 ? i5 / (nPts - 1) : 0.5) * CW - 0.4, P.y1 - 0.02, 0.8, 0.24,
3225
+ sh.push(txSp(MX + (nPts > 1 ? i5 / (nPts - 1) : 0.5) * CW - 0.4, plotBottom - 0.22, 0.8, 0.2,
3182
3226
  [[{ t: String(lb), sz: 9.5, col: S.faint, font: S.font }]], { align: 'ctr' }));
3183
3227
  });
3184
3228
  }
@@ -3370,8 +3414,8 @@ function slidesOf(model, S) {
3370
3414
  var iy = iR.y;
3371
3415
  var capH2 = img.caption ? 0.32 : 0;
3372
3416
  var ih = Math.max(1.2, iR.h);
3373
- imageLayoutShapes(sh, S, layout, img, items, sec.points || [], isPh, fit, iy, iy + ih);
3374
- if (img.caption) sh.push(txSp(MX, iy + ih + 0.04, CW, capH2, [[{ t: img.caption, sz: 10.5, col: S.faint, font: S.font }]]));
3417
+ var capYImg = imageLayoutShapes(sh, S, layout, img, items, sec.points || [], isPh, fit, iy, iy + ih);
3418
+ if (img.caption) sh.push(txSp(MX, capYImg + 0.04, CW, capH2, [[{ t: img.caption, sz: 10.5, col: S.faint, font: S.font }]]));
3375
3419
  } else if (type === 'donut') {
3376
3420
  var dcn = sec.chart || {};
3377
3421
  if (dcn.labels && dcn.values) donutChart(sh, dcn, S, dcn.colors || donutColors(model.style, S, model.theme));
@@ -3688,7 +3732,7 @@ function slidesOf(model, S) {
3688
3732
  sh.push(shape('rect', x, ly2 + rowHP / 2 - 0.06, 0.12, 0.12, S.accent));
3689
3733
  sh.push(txSp(x + 0.28, ly2, w - 0.4, rowHP - 0.04,
3690
3734
  [[{ t: pt[0] + ' ', sz: fzP, b: 1, col: S.ink, font: S.font },
3691
- { t: pt[1], sz: fzP - 1, col: S.body, font: S.font }]]));
3735
+ { t: pt[1], sz: snapFont(fzP - 1), col: S.body, font: S.font }]]));
3692
3736
  });
3693
3737
  };
3694
3738
  if (lt2 === 'table') {
@@ -3809,7 +3853,7 @@ function slidesOf(model, S) {
3809
3853
  sh.push(shape('rect', ptsR.x, y11 + rowHPt / 2 - P2.markSize / 2, P2.markSize, P2.markSize, S.accent));
3810
3854
  sh.push(txSp(ptsR.x + 0.32, y11, textW, rowHPt - 0.04,
3811
3855
  [[{ t: p[0] + ' ', sz: fzP, b: 1, col: S.ink, font: S.font },
3812
- { t: p[1], sz: fzP - 1, col: S.body, font: S.font }]]));
3856
+ { t: p[1], sz: snapFont(fzP - 1), col: S.body, font: S.font }]]));
3813
3857
  });
3814
3858
  if (hasM) {
3815
3859
  var gx2 = PW - MX - nm2 * mw2;
@@ -0,0 +1,181 @@
1
+ {
2
+ "version": 1,
3
+ "skill": "top-ppt-html",
4
+ "description": "Keyword/heuristic trigger coverage against SKILL.md frontmatter description. Not an LLM eval — CI gates regressions when trigger keywords drift.",
5
+ "how_to_extend": [
6
+ "Add a positive query that should select this skill (报告/路演/PPT/HTML/调研…).",
7
+ "Add a negative query that must NOT select it (coding/video/edit-existing-pptx…).",
8
+ "Each entry: {id, query, expect: 'hit'|'miss', notes?}",
9
+ "Runner: python3 scripts/check_triggers.py — matches query tokens against description keywords extracted from SKILL.md.",
10
+ "Wire: package_skill.py --check invokes check_triggers; also npm run check."
11
+ ],
12
+ "positive": [
13
+ {
14
+ "id": "P01",
15
+ "query": "帮我做一份季度经营分析报告",
16
+ "expect": "hit"
17
+ },
18
+ {
19
+ "id": "P02",
20
+ "query": "明天路演用的融资 PPT,10页左右",
21
+ "expect": "hit"
22
+ },
23
+ {
24
+ "id": "P03",
25
+ "query": "生成一份可翻页的 HTML 演示文稿",
26
+ "expect": "hit"
27
+ },
28
+ {
29
+ "id": "P04",
30
+ "query": "把调研材料做成 slides deck",
31
+ "expect": "hit"
32
+ },
33
+ {
34
+ "id": "P05",
35
+ "query": "写一份麦肯锡风格的对标分析研究报告",
36
+ "expect": "hit"
37
+ },
38
+ {
39
+ "id": "P06",
40
+ "query": "项目复盘汇报 PPTX,要能编辑",
41
+ "expect": "hit"
42
+ },
43
+ {
44
+ "id": "P07",
45
+ "query": "画一张系统架构拓扑图,图为王",
46
+ "expect": "hit"
47
+ },
48
+ {
49
+ "id": "P08",
50
+ "query": "泳道流程图 + 方案说明页",
51
+ "expect": "hit"
52
+ },
53
+ {
54
+ "id": "P09",
55
+ "query": "白皮书大纲做成网页报告",
56
+ "expect": "hit"
57
+ },
58
+ {
59
+ "id": "P10",
60
+ "query": "评测报告可视化,导出 HTML 和 PPT",
61
+ "expect": "hit"
62
+ },
63
+ {
64
+ "id": "P11",
65
+ "query": "商务汇报用的一页一主张演示",
66
+ "expect": "hit"
67
+ },
68
+ {
69
+ "id": "P12",
70
+ "query": "快速模式一键出稿,少问一句",
71
+ "expect": "hit"
72
+ },
73
+ {
74
+ "id": "P13",
75
+ "query": "fast mode generate a pitch deck",
76
+ "expect": "hit"
77
+ },
78
+ {
79
+ "id": "P14",
80
+ "query": "咨询报告:发现、证据、so-what",
81
+ "expect": "hit"
82
+ },
83
+ {
84
+ "id": "P15",
85
+ "query": "优化这份报告的排版版式和配色密度",
86
+ "expect": "hit"
87
+ },
88
+ {
89
+ "id": "P16",
90
+ "query": "把数据做成可视化经营分析 deck",
91
+ "expect": "hit"
92
+ },
93
+ {
94
+ "id": "P17",
95
+ "query": "发布会演讲 PPT,亮暗双主题",
96
+ "expect": "hit"
97
+ },
98
+ {
99
+ "id": "P18",
100
+ "query": "行业调研 + 对标分析 HTML 报告",
101
+ "expect": "hit"
102
+ },
103
+ {
104
+ "id": "P19",
105
+ "query": "直接生成项目汇报 slides",
106
+ "expect": "hit"
107
+ },
108
+ {
109
+ "id": "P20",
110
+ "query": "高保真 1:1 导出可编辑 PPTX",
111
+ "expect": "hit"
112
+ },
113
+ {
114
+ "id": "P21",
115
+ "query": "做个信息架构图和分层带",
116
+ "expect": "hit"
117
+ },
118
+ {
119
+ "id": "P22",
120
+ "query": "董事会汇报材料,正式演示风格",
121
+ "expect": "hit"
122
+ }
123
+ ],
124
+ "negative": [
125
+ {
126
+ "id": "N01",
127
+ "query": "帮我写一个 React 组件库并跑单测",
128
+ "expect": "miss"
129
+ },
130
+ {
131
+ "id": "N02",
132
+ "query": "debug 这段 Python 报错",
133
+ "expect": "miss"
134
+ },
135
+ {
136
+ "id": "N03",
137
+ "query": "生成一段产品宣传视频脚本并渲染成 mp4",
138
+ "expect": "miss"
139
+ },
140
+ {
141
+ "id": "N04",
142
+ "query": "用 Midjourney 生成一张产品海报图",
143
+ "expect": "miss"
144
+ },
145
+ {
146
+ "id": "N05",
147
+ "query": "直接改这个已有的 pptx 里第三页的字号",
148
+ "expect": "miss"
149
+ },
150
+ {
151
+ "id": "N06",
152
+ "query": "打开 Word 文档把第二段改成被动语态",
153
+ "expect": "miss"
154
+ },
155
+ {
156
+ "id": "N07",
157
+ "query": "搭建一个电商官网前端,不要报告",
158
+ "expect": "miss"
159
+ },
160
+ {
161
+ "id": "N08",
162
+ "query": "给我写 SQL 迁移脚本",
163
+ "expect": "miss"
164
+ },
165
+ {
166
+ "id": "N09",
167
+ "query": "配置 nginx 反向代理",
168
+ "expect": "miss"
169
+ },
170
+ {
171
+ "id": "N10",
172
+ "query": "把这段代码 refactor 成 TypeScript",
173
+ "expect": "miss"
174
+ },
175
+ {
176
+ "id": "N11",
177
+ "query": "剪辑这段会议录像加字幕",
178
+ "expect": "miss"
179
+ }
180
+ ]
181
+ }
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "top-ppt-html",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "private": true,
5
- "description": "TopPPT HTML:报告 / 演示 / 信息架构图技能。单文件 HTML + 版式保真的可编辑 PPTX;布局骨架 P1–P12;模型单写;strict 0/0 交付。",
5
+ "description": "TopPPT HTML:优雅大气的正式场合演讲/汇报甲板。单文件 HTML + 版式保真可编辑 PPTX;布局骨架 P1–P12;模型单写;strict 0/0 交付。",
6
6
  "license": "MIT",
7
7
  "repository": {
8
8
  "type": "git",
@@ -24,7 +24,8 @@
24
24
  "regression": "python3 scripts/regression.py",
25
25
  "negative": "python3 scripts/negative_tests.py",
26
26
  "package": "python3 scripts/package_skill.py",
27
- "check": "python3 scripts/package_skill.py --check"
27
+ "check": "python3 scripts/package_skill.py --check",
28
+ "triggers": "python3 scripts/check_triggers.py"
28
29
  },
29
30
  "dependencies": {
30
31
  "pptxgenjs": "^4.0.0"
@@ -0,0 +1,42 @@
1
+ # 图表选型决策树(L2)
2
+
3
+ > **何时读**:选图 / 分析意图→图型;常读入口仍是 `playbook.md` §五(核图 8 + 多样性摘要)。读完即停。
4
+ > 完整登记与代码 → `extract_snippet.py --chart <类型>`;误用纪律 → `charts.md`(先 `charts-discipline`,核图 8,extended 按需)。
5
+
6
+ ## 决策表
7
+
8
+ | 分析意图(读者要得出的结论) | 首选 | 次选 | 禁用 / 改判条件 |
9
+ |---------------------------|------|------|----------------|
10
+ | 谁大谁小 | `hbar` | `lollipop` / `bar` | 类别 >8 → Top7 + 附录 |
11
+ | 随时间怎么变 | `line` | `area` / `dualline` | 时间点 >8 不标点值 |
12
+ | 占比是多少 | `donut` | `pie` / `multidonut` | 扇区 >5 → 合并"其他"或 `treemap` |
13
+ | 每 1% 的直觉 | `waffle` | `donut` | 类别 >3 改 `marimekko` |
14
+ | 结构在变形 | `streamgraph` | `stackline` | 系列 >6 合并 |
15
+ | 总量 × 构成双编码 | `marimekko` | `treemap` | 列 >6 / 段 >4 → 拆 |
16
+ | 份额悬殊(头部集中) | `treemap` | `donut` | 叶 >16 → 合并小项 |
17
+ | 从 A 到 B 是谁贡献的 | `waterfall` | `pareto` | 段 >6 → 合并 |
18
+ | 主要矛盾是哪几个 | `pareto` | `waterfall` | 类别 >7 → 合并 |
19
+ | 转化/流失在哪一环 | `funnel` | `sankey` | 层 >5 → 改 `hbar` |
20
+ | 多对多的流向 | `sankey` | `network` | 节点 >12 / 流带 >24 → 拆页 |
21
+ | 谁和谁相连 | `network` | `diagram` | 节点 >18 / 边 >30 → 拆页 |
22
+ | 两期谁升谁降 | `slope` | `dumbbell` | 系列 >6 → 取 Top 6 |
23
+ | 单指标前后对比(多对象) | `dumbbell` | `vsbar` | 行 >6 → 拆页 |
24
+ | 实际 vs 目标(含区间) | `bulletchart` | `bullet` | 行 >6 → 拆页 |
25
+ | 达成率(多指标同心) | `radialbar` | `gauge` | 环 >5 → 改 `bullet` |
26
+ | 一个值够不够 | `gauge` | `radialbar` | 单值叙事,勿与图并存 |
27
+ | 分布不是均值 | `boxplot` | `dotplot` | 组 >8 → 拆页 |
28
+ | 双维定位 + 第三维权重 | `bubble` | `scatter` | 气泡 >8 → 标注关键项 |
29
+ | 六维能力画像 | `radar` | `rose` | 维度 >6 → 拆两组 |
30
+ | 区间波动(开高低收) | `candlestick` | `line` | 蜡烛 >12 → 聚合 |
31
+ | 多项目完成度 | `progress` | `bullet` | 行 >6 → 拆页 |
32
+ | 迷你趋势(卡内) | `sparkline` | — | 只用于指标卡,不与大图并存 |
33
+
34
+ ## 七种最常见的误用(出现即改判)
35
+
36
+ 1. 用 `bar` 表达占比 → 改 `donut`/`stackline`/`waffle`。
37
+ 2. 用 `donut` 表达 8 个类别 → 合并或改 `treemap`。
38
+ 3. 用 `line` 表达类别对比(无时间轴)→ 改 `hbar`。
39
+ 4. 用 `table` 表达趋势 → 改 `line`/`area`。
40
+ 5. 用均值型图表表达分布 → 改 `boxplot`/`dotplot`。
41
+ 6. 同一页放两张同型图 → 改 `split`/`halftable` 并让两图**编码不同维度**。
42
+ 7. 多系列图用单色明度阶梯(分不清) → 用 `f-c1~c5` 编码色板(见 playbook §八)。
@@ -1,6 +1,6 @@
1
1
  # 默认生成面(L1.5 · Mode A 主读 · ≤6KB)
2
2
 
3
- > **Mode A / Fast 演示的首要读面**(正式场合 · 大气演讲)。完整决策见 `playbook.md`;工艺清单见 `presentation-craft.md`;代码用 `extract_snippet.py`。
3
+ > **Mode A / Fast 演示的首要读面**(正式场合 · 大气演讲)。完整决策见 `playbook.md`;工艺清单见 `presentation-craft.md`;插画/配图见 `illustration-layout.md`;代码用 `extract_snippet.py`。
4
4
  > Mode B/C 能力保留——**需要时**再读 modes / layouts-*;勿把密排/架构默认反向污染 A。
5
5
 
6
6
  ## A 默认三件套
@@ -53,9 +53,10 @@
53
53
  ```
54
54
  scaffold_report → 只填 REPORT_MODEL → render_from_model --inplace
55
55
  → validate_report --strict # presentation 自动 --layout-qa
56
- → quality_gate --deliver →(可选)pptx
56
+ → quality_gate --deliver →(用户要 PPTX 时)B 通道 build_pptx → validate_pptx
57
57
  ```
58
58
 
59
59
  ## 长文与密度(Mode A)
60
60
 
61
61
  一屏一主张;证据用卡/列表或跟进页。**禁止**为稀疏 demo 感删实质。溢出顺序:重构 → 拆页 → 换 V/栅格 → 有限 fontShrink。详见 `presentation-craft.md`「长文与信息承载」。
62
+ 配图/插画页:caption+so-what、安全边距、勿与大图双重心——`illustration-layout.md`。
@@ -0,0 +1,39 @@
1
+ # 插画 / 非数据配图 brief(L2 · ≤4KB)
2
+
3
+ > **何时读**:页含情绪图 / 产品图 / 截图 / 示意图 / `image.placeholder`;或 Mode A 需要 full-bleed 照片+主张叠字。
4
+ > **何时不读**:纯数据图表选型(走 playbook §五 / `charts.md`)。
5
+ > **取码**:`extract_snippet.py --task image-layout`(`components.md` §11c);勿整读 `components-atoms.md`。
6
+
7
+ ## 配图 vs 数据图(互斥优先)
8
+
9
+ | 意图 | 用什么 | 不要 |
10
+ |------|--------|------|
11
+ | 趋势 / 构成 / 对比 / 排名 | 数据图(核图 8 优先) | 用照片代替数据 |
12
+ | 氛围 / 品牌 / 产品外观 / UI 截图 | `<img>` / `.media` / `image.placeholder` | 硬画假图表 |
13
+ | 无素材但仍需图位 | `image.placeholder` + `.media--ph` | 留空或塞无关图 |
14
+
15
+ **一页一主视觉**:同页不要「大照片 + 大图表」双重心(FAIL 级审美风险);icon 可点缀,chart 占主位时照片改小或拆页。
16
+
17
+ ## 版式与安全边距
18
+
19
+ - **安全边距**:距版心边缘 ≥ 24px(演示投影更宽松);文字不得压在图片关键焦点上。
20
+ - **图文共存**:半幅图(half)→ 图左/上 + 注右/下;注含 **caption(图注)+ so-what(含义一句)**。
21
+ - **不重叠**:标题 / 标签 / 图例不得与照片主体或 icon 碰撞;必要叠字用半透明底或高对比条。
22
+ - **icon + chart**:icon 在注释列或卡眉,不进 SVG 绘图区;每屏 icon 仍 3–8。
23
+
24
+ ## Mode A · full-bleed 照片 + 主张叠字
25
+
26
+ 1. 仅用于封面 / 章节幕 / 金句休止 / 收尾 —— **不做证据页**。
27
+ 2. 主张句叠在照片暗侧或统一遮罩条上;对比度满足 WCAG(正文感 ≥4.5:1)。
28
+ 3. `layout: bleed` + 安全区内 claim;勿在 bleed 页再塞密表/多卡。
29
+ 4. 必须有 **caption 或来源/版权**(可沉 `.fig__cap` / footnote);证据含义用跟进页,不塞进 bleed。
30
+
31
+ ## 清单(写模型前 10 秒)
32
+
33
+ - [ ] 这页是数据图还是插画?二者勿抢主位
34
+ - [ ] 有 caption + so-what(或明确「氛围休止页无需 so-what」)
35
+ - [ ] 无文字压焦点、无标签重叠、边距够
36
+ - [ ] 无素材 → placeholder,不留空洞
37
+ - [ ] 校验:`validate_report` 对缺 caption/so-what 的配图页 WARN
38
+
39
+ > 详细几何与六版式(full/half/bleed/grid/compare/wall)→ `extract_snippet.py --task image-layout`。
@@ -74,7 +74,7 @@
74
74
 
75
75
  ## 模式 A · 演示汇报 `presentation`(assets/templates/presentation.html)
76
76
 
77
- 台上讲给人听,3 秒抓住主张。工艺清单 → `presentation-craft.md`;默认面 → `default-surface.md`。
77
+ 正式场合演讲甲板:优雅、大气、一屏一主张;3 秒抓住结论。工艺 → `presentation-craft.md`;默认面 → `default-surface.md`。**非**咨询密排 dump(那是 Mode B)。
78
78
 
79
79
  要点回顾:
80
80
 
@@ -20,6 +20,30 @@
20
20
  之后才进入生成(SKILL.md 工作流),规划即填写 REPORT_MODEL 的直接输入
21
21
  ```
22
22
 
23
+ ## 〇、轻量最小集(Fast / 轻量路径 · 非七步)
24
+
25
+ > **不强迫完整七步**,但禁止「零大纲直接 scaffold」。路演/汇报材料杂时尤其需要这一屏。
26
+
27
+ 写在内部笔记(≤1 屏)即可:
28
+
29
+ 1. **核心主张一句话**(≤30 字;含判断/数字更好)。
30
+ 2. **页清单**(每行三列):`claim`(本页主张) / `pageType` / `chart`(无图写 `—` 或 `image`/`placeholder`)。
31
+
32
+ 示例:
33
+
34
+ ```
35
+ 主张:Q3 增长靠转化而非流量,优先修结账漏斗
36
+ 1. 议程 | agenda | —
37
+ 2. 转化率跌 4pt | kpi | —
38
+ 3. 漏斗三段对比 | bar | funnel
39
+ 4. 竞品截图+含义 | image | —
40
+ 5. 行动三项 | points | —
41
+ ```
42
+
43
+ 之后进入 playbook §二轻量命令链。完整路径仍走下方七步法。
44
+
45
+ ---
46
+
23
47
  > **为什么前置证据表与故事线脑暴**:直接从材料跳到单版大纲,等于用第一条想到的叙事结构绑架全部材料——证据冲突会被静默抹平、弱枝论点会混进主张树。**先摊开证据、再发散故事线、最后收敛**,是咨询材料的标准做法。
24
48
 
25
49
  ### ① 意图解析(问自己四个问题,写进内部笔记,不进报告)
@@ -0,0 +1,35 @@
1
+ # 页型选型矩阵(L2)
2
+
3
+ > **何时读**:选页型 / 意图→页型映射;常读入口仍是 `playbook.md`。读完即停。
4
+ > 自动选型:`python scripts/recommend_layout.py --mode A --intent "…" --json`
5
+ > 穷举表(内容形态 → 版式 → PPTX 页型)见 `components.md` §46;密度档 `components.md` §46b;组合见 playbook §四。
6
+
7
+ | 我要表达 | 首选页型 | 次选 | 关键约束 |
8
+ |---------|---------|------|---------|
9
+ | 要点式并列主张(默认页) | `points` | `cards` | 每卡宜 3–5 条;更多拆卡/跟进页,勿截断条目 |
10
+ | 现状基线 / 指标快照 | `metrics` | `kpi` | 4–6 个;单数压场用 `kpi` |
11
+ | 单个核心数字压场 | `kpi` | `metrics` | hero 一数一结论 |
12
+ | 多维对标清单 | `table` | `halftable` | ≤8 行(research ≤16) |
13
+ | 时间趋势 / 爬坡 | `bar`(chart.type=line/area/dualline) | `exhibit` | 时间点 >8 改折线 |
14
+ | 构成占比 | `donut`(pie/multidonut/waffle) | `halftable` / **V3 KPI** | 扇区 ≤5,最小扇区 ≥8%;**极偏(min&lt;5% 或 max/min&gt;20)禁 donut→V3** |
15
+ | 排名 / 大小对比 | `bar`(chart.type=hbar/lollipop/pareto) | `table` | 类别 >8 取 Top 7 + 附录 |
16
+ | 现状 vs 目标 | `bullet` / `comparison` | `bar`(vsbar/bulletchart) | 目标线与实际条同量纲 |
17
+ | 两期升降(谁升谁降) | `bar`(slope/dumbbell) | `table` | 两端都要标数值 |
18
+ | 双维分布 / 优先级 | `bar`(scatter/bubble) | `matrix` | 气泡半径 ∝ √值 |
19
+ | 分布 / 离散度 | `boxplot` | `bar`(dotplot) | 组数 ≤8;箱线四件齐备 |
20
+ | 增减归因(A→B) | `bar`(waterfall) | `table` | 每段标变化量 + 合计收口 |
21
+ | 转化 / 筛选漏斗 | `bar`(funnel) | `sankey` | 层数 ≤5 |
22
+ | 计划排期(并行) | `bar`(gantt) | `timeline` | 里程碑叙事用 `timeline`,勿混 |
23
+ | 里程碑 / 路线叙事 | `timeline` | `steps` | 3–5 个,每个 ≤2 行 |
24
+ | 步骤 / 实施节奏 | `steps` | `timeline` | 3–6 步;高亮步 ≤2 处 |
25
+ | 二维强度对标 | `heatmap` | `matrix` | 行列 ≤5×5;只用强调色明度阶梯 |
26
+ | 定位 / 优先级 / 象限 | `matrix` | `bar`(scatter) | ≤3×3 |
27
+ | 层级递进 / 价值阶梯 | `pyramid` | `diagram` | 3–5 层;强调层 ≤1 |
28
+ | 关键判断 / 金句休止 | `quote` | `points` | 全文 1–2 处,多了廉价 |
29
+ | 完整论述(发现→证据→含义) | `twocol`(research R1) | `threecol` | 段 ≤200 字;标题必须结论句 |
30
+ | 数据证据页(主力) | `exhibit`(R2) | `split` | 全篇 Exhibit 连续编号 |
31
+ | 三栏并列论点 | `threecol`(R6) | `cards` | 每栏 ≤150 字 |
32
+ | 系统分层架构 | `diagram` | `bar`(chart.type=network) | 节点 ≤24;层 ≤4 |
33
+ | 流程 / 职责协作 | `lane` | `diagram` | 每行 ≤6 步;正交折线优先 |
34
+ | 素材图片(实拍/截图) | `image` | `split` | 六版式;无图用 `image.placeholder` |
35
+ | 待核实项收口 | `flags` 字段 | `table` | 标色必须配说明 |