@taloswork/ose-shared 0.1.6 → 0.1.8
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/package.json +3 -3
- package/skills/document/SKILL.md +32 -17
- package/skills/document/art-directions/base.css +23 -0
- package/skills/document/art-directions/cinematic-depth.css +6 -0
- package/skills/document/art-directions/collage-paper.css +8 -0
- package/skills/document/art-directions/editorial-cut.css +8 -0
- package/skills/document/art-directions/geometric-pop.css +9 -0
- package/skills/document/art-directions/gradient-mesh.css +6 -0
- package/skills/document/art-directions/illustrated-doodle.css +8 -0
- package/skills/document/art-directions/luxury-ornament.css +6 -0
- package/skills/document/art-directions/maximalist-blocks.css +9 -0
- package/skills/document/art-directions/technical-grid.css +6 -0
- package/skills/document/assets/fonts/fonts.json +2 -2
- package/skills/document/bin/deck-build.cjs +266 -10
- package/skills/document/bin/doc-convert.cjs +66 -28
- package/skills/document/bin/doc-gen.cjs +8 -9
- package/skills/document/bin/html2pptx.cjs +243 -24
- package/skills/document/bin/pptx-clone.cjs +41 -30
- package/skills/document/bin/pptx-embed-fonts.cjs +6 -2
- package/skills/document/bin/pptx-slide.cjs +46 -50
- package/skills/document/catalog.json +11 -0
- package/skills/document/components/base.css +45 -0
- package/skills/document/components/profiles/clean.css +2 -0
- package/skills/document/components/profiles/editorial.css +3 -0
- package/skills/document/components/profiles/glass.css +2 -0
- package/skills/document/components/profiles/luxury.css +3 -0
- package/skills/document/components/profiles/organic.css +2 -0
- package/skills/document/components/profiles/poster.css +3 -0
- package/skills/document/content-pipeline.md +110 -54
- package/skills/document/deck-design.md +24 -15
- package/skills/document/layouts/README.md +41 -12
- package/skills/document/layouts/blocks-2x2.tpl +19 -9
- package/skills/document/layouts/business-model.tpl +6 -0
- package/skills/document/layouts/cards-3.tpl +1 -1
- package/skills/document/layouts/customer-proof.tpl +6 -0
- package/skills/document/layouts/funding-ask.tpl +5 -0
- package/skills/document/layouts/market-rings.tpl +5 -0
- package/skills/document/layouts/org-tree.tpl +1 -1
- package/skills/document/layouts/pitch-problem.tpl +6 -0
- package/skills/document/layouts/pitch-solution.tpl +5 -0
- package/skills/document/layouts/pricing-tiers.tpl +5 -0
- package/skills/document/layouts/product-device.tpl +6 -0
- package/skills/document/layouts/profiles.json +24 -0
- package/skills/document/layouts/slots.json +1 -1
- package/skills/document/layouts/steps-vertical.tpl +1 -1
- package/skills/document/layouts/team-founders.tpl +5 -0
- package/skills/document/layouts/traction-milestones.tpl +6 -0
- package/skills/document/media-styles/cinematic.css +2 -0
- package/skills/document/media-styles/clean-product.css +2 -0
- package/skills/document/media-styles/cutout-collage.css +3 -0
- package/skills/document/media-styles/device-stage.css +3 -0
- package/skills/document/media-styles/editorial-photo.css +3 -0
- package/skills/document/media-styles/illustrated.css +2 -0
- package/skills/document/media-styles/spatial-3d.css +3 -0
- package/skills/document/motion/mckinsey-photo.json +22 -0
- package/skills/document/motion/prismatic-3d.json +31 -0
- package/skills/document/packs/README.md +7 -3
- package/skills/document/packs/mckinsey-photo/backdrop.html +6 -0
- package/skills/document/packs/mckinsey-photo/layouts/cover-image.tpl +5 -0
- package/skills/document/packs/mckinsey-photo/layouts/cover.tpl +5 -0
- package/skills/document/packs/mckinsey-photo/layouts/image-left.tpl +5 -0
- package/skills/document/packs/mckinsey-photo/layouts/numbered-brief.tpl +5 -0
- package/skills/document/packs/mckinsey-photo/pack.css +27 -0
- package/skills/document/packs/prismatic-3d/backdrop.html +4 -0
- package/skills/document/packs/prismatic-3d/layouts/big-stat.tpl +6 -0
- package/skills/document/packs/prismatic-3d/layouts/cover.tpl +9 -0
- package/skills/document/packs/prismatic-3d/layouts/section-image.tpl +6 -0
- package/skills/document/packs/prismatic-3d/pack.css +28 -0
- package/skills/document/recipes/agency-pitch.json +13 -0
- package/skills/document/recipes/product-launch.json +13 -0
- package/skills/document/recipes/startup-fundraising.json +19 -0
- package/skills/document/styles/README.md +13 -6
- package/skills/document/styles/_contract-defaults.css +1 -1
- package/skills/document/styles/_samples/_groups/biz-premium.webp +0 -0
- package/skills/document/styles/_samples/_groups/creative.webp +0 -0
- package/skills/document/styles/_samples/_groups/editorial.webp +0 -0
- package/skills/document/styles/_samples/_groups/minimal.webp +0 -0
- package/skills/document/styles/_samples/_groups/natural.webp +0 -0
- package/skills/document/styles/_samples/_groups/tech-future.webp +0 -0
- package/skills/document/styles/_samples/bistro-warm.webp +0 -0
- package/skills/document/styles/_samples/board-brief.webp +0 -0
- package/skills/document/styles/_samples/bold-clash.webp +0 -0
- package/skills/document/styles/_samples/campus-teal.webp +0 -0
- package/skills/document/styles/_samples/clinic-care.webp +0 -0
- package/skills/document/styles/_samples/dark-glass.webp +0 -0
- package/skills/document/styles/_samples/gov-brief.webp +0 -0
- package/skills/document/styles/_samples/grid-tech.webp +0 -0
- package/skills/document/styles/_samples/legal-slate.webp +0 -0
- package/skills/document/styles/_samples/mckinsey-photo.webp +0 -0
- package/skills/document/styles/_samples/memphis.webp +0 -0
- package/skills/document/styles/_samples/neon-cyber.webp +0 -0
- package/skills/document/styles/_samples/organic-earth.webp +0 -0
- package/skills/document/styles/_samples/pastel-saas.webp +0 -0
- package/skills/document/styles/_samples/portfolio-noir.webp +0 -0
- package/skills/document/styles/_samples/press-room.webp +0 -0
- package/skills/document/styles/_samples/prismatic-3d.webp +0 -0
- package/skills/document/styles/_samples/retro-press.webp +0 -0
- package/skills/document/styles/_samples/sport-arena.webp +0 -0
- package/skills/document/styles/_samples/wedding-blush.webp +0 -0
- package/skills/document/styles/dark-glass/backdrop.html +7 -3
- package/skills/document/styles/dark-glass/skin.css +1 -0
- package/skills/document/styles/portfolio-noir/skin.css +3 -0
- package/skills/document/theme-system.json +68 -0
- package/skills/document/theme-system.md +101 -0
|
@@ -9820,11 +9820,40 @@ var import_promises = require("node:fs/promises");
|
|
|
9820
9820
|
|
|
9821
9821
|
// packages/core/dist/document/pptx-slide.js
|
|
9822
9822
|
var import_jszip = __toESM(require_lib3(), 1);
|
|
9823
|
+
|
|
9824
|
+
// packages/core/dist/document/pptx-register-slide.js
|
|
9823
9825
|
var SLIDE_CT = "application/vnd.openxmlformats-officedocument.presentationml.slide+xml";
|
|
9824
9826
|
var SLIDE_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide";
|
|
9827
|
+
async function text(zip, path) {
|
|
9828
|
+
const f = zip.file(path);
|
|
9829
|
+
if (!f)
|
|
9830
|
+
throw new Error(`not a PowerPoint file (${path} missing)`);
|
|
9831
|
+
return f.async("string");
|
|
9832
|
+
}
|
|
9833
|
+
async function registerSlidePart(zip, newNum, newXmlPath) {
|
|
9834
|
+
const ctPath = "[Content_Types].xml";
|
|
9835
|
+
const ct = await text(zip, ctPath);
|
|
9836
|
+
if (!ct.includes(`PartName="/${newXmlPath}"`)) {
|
|
9837
|
+
zip.file(ctPath, ct.replace("</Types>", `<Override PartName="/${newXmlPath}" ContentType="${SLIDE_CT}"/></Types>`));
|
|
9838
|
+
}
|
|
9839
|
+
const presRelsPath = "ppt/_rels/presentation.xml.rels";
|
|
9840
|
+
const presRels = await text(zip, presRelsPath);
|
|
9841
|
+
const maxRid = Math.max(0, ...[...presRels.matchAll(/Id="rId(\d+)"/g)].map((m) => Number(m[1])));
|
|
9842
|
+
const newRid = `rId${maxRid + 1}`;
|
|
9843
|
+
zip.file(presRelsPath, presRels.replace("</Relationships>", `<Relationship Id="${newRid}" Type="${SLIDE_REL_TYPE}" Target="slides/slide${newNum}.xml"/></Relationships>`));
|
|
9844
|
+
const presPath = "ppt/presentation.xml";
|
|
9845
|
+
const pres = await text(zip, presPath);
|
|
9846
|
+
const maxSldId = Math.max(255, ...[...pres.matchAll(/<p:sldId id="(\d+)"/g)].map((m) => Number(m[1])));
|
|
9847
|
+
const updated = pres.replace("</p:sldIdLst>", `<p:sldId id="${maxSldId + 1}" r:id="${newRid}"/></p:sldIdLst>`);
|
|
9848
|
+
if (updated === pres)
|
|
9849
|
+
throw new Error("could not locate the slide list in presentation.xml");
|
|
9850
|
+
zip.file(presPath, updated);
|
|
9851
|
+
}
|
|
9852
|
+
|
|
9853
|
+
// packages/core/dist/document/pptx-slide.js
|
|
9825
9854
|
var LAYOUT_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout";
|
|
9826
9855
|
var BLANK_SLIDE_XML = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<p:sld xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main"><p:cSld><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr/></p:spTree></p:cSld><p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr></p:sld>';
|
|
9827
|
-
async function
|
|
9856
|
+
async function text2(zip, path) {
|
|
9828
9857
|
const f = zip.file(path);
|
|
9829
9858
|
if (!f)
|
|
9830
9859
|
throw new Error(`not a PowerPoint file (${path} missing)`);
|
|
@@ -9872,29 +9901,14 @@ async function addBlankSlide(bytes, opts = {}) {
|
|
|
9872
9901
|
zip.file(newXmlPath, BLANK_SLIDE_XML);
|
|
9873
9902
|
zip.file(`ppt/slides/_rels/slide${newNum}.xml.rels`, `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
9874
9903
|
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="${LAYOUT_REL_TYPE}" Target="../slideLayouts/slideLayout${layout}.xml"/></Relationships>`);
|
|
9875
|
-
|
|
9876
|
-
if (!ct.includes(`PartName="/${newXmlPath}"`)) {
|
|
9877
|
-
zip.file("[Content_Types].xml", ct.replace("</Types>", `<Override PartName="/${newXmlPath}" ContentType="${SLIDE_CT}"/></Types>`));
|
|
9878
|
-
}
|
|
9879
|
-
const presRelsPath = "ppt/_rels/presentation.xml.rels";
|
|
9880
|
-
const presRels = await text(zip, presRelsPath);
|
|
9881
|
-
const maxRid = Math.max(0, ...[...presRels.matchAll(/Id="rId(\d+)"/g)].map((m) => Number(m[1])));
|
|
9882
|
-
const newRid = `rId${maxRid + 1}`;
|
|
9883
|
-
zip.file(presRelsPath, presRels.replace("</Relationships>", `<Relationship Id="${newRid}" Type="${SLIDE_REL_TYPE}" Target="slides/slide${newNum}.xml"/></Relationships>`));
|
|
9884
|
-
const presPath = "ppt/presentation.xml";
|
|
9885
|
-
const pres = await text(zip, presPath);
|
|
9886
|
-
const maxSldId = Math.max(255, ...[...pres.matchAll(/<p:sldId id="(\d+)"/g)].map((m) => Number(m[1])));
|
|
9887
|
-
const updated = pres.replace("</p:sldIdLst>", `<p:sldId id="${maxSldId + 1}" r:id="${newRid}"/></p:sldIdLst>`);
|
|
9888
|
-
if (updated === pres)
|
|
9889
|
-
throw new Error("could not locate the slide list in presentation.xml");
|
|
9890
|
-
zip.file(presPath, updated);
|
|
9904
|
+
await registerSlidePart(zip, newNum, newXmlPath);
|
|
9891
9905
|
const out2 = await zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
|
|
9892
9906
|
return { bytes: new Uint8Array(out2), newSlideNumber: newNum, layout };
|
|
9893
9907
|
}
|
|
9894
9908
|
async function reorderPptxSlides(bytes, order) {
|
|
9895
9909
|
const zip = await load(bytes);
|
|
9896
9910
|
const presPath = "ppt/presentation.xml";
|
|
9897
|
-
const pres = await
|
|
9911
|
+
const pres = await text2(zip, presPath);
|
|
9898
9912
|
const listMatch = /(<p:sldIdLst\b[^>]*>)([\s\S]*?)(<\/p:sldIdLst>)/.exec(pres);
|
|
9899
9913
|
if (!listMatch)
|
|
9900
9914
|
throw new Error("no <p:sldIdLst> in presentation.xml (corrupt deck?)");
|
|
@@ -9965,9 +9979,9 @@ function unescXml(s) {
|
|
|
9965
9979
|
}
|
|
9966
9980
|
});
|
|
9967
9981
|
}
|
|
9968
|
-
function visualWidth(
|
|
9982
|
+
function visualWidth(text4) {
|
|
9969
9983
|
let w = 0;
|
|
9970
|
-
for (const ch of
|
|
9984
|
+
for (const ch of text4) {
|
|
9971
9985
|
const cp = ch.codePointAt(0);
|
|
9972
9986
|
if (ch === " " || ch === " ")
|
|
9973
9987
|
w += 0.35;
|
|
@@ -9996,9 +10010,9 @@ function replaceTextAcrossRuns(xml, find, replacement, opts) {
|
|
|
9996
10010
|
const segs = [];
|
|
9997
10011
|
let flat = "";
|
|
9998
10012
|
for (const m of para.matchAll(textRe)) {
|
|
9999
|
-
const
|
|
10000
|
-
segs.push({ el: m[0], attrs: m[1] ?? "", text:
|
|
10001
|
-
flat +=
|
|
10013
|
+
const text4 = unescXml(m[2]);
|
|
10014
|
+
segs.push({ el: m[0], attrs: m[1] ?? "", text: text4, start: flat.length });
|
|
10015
|
+
flat += text4;
|
|
10002
10016
|
}
|
|
10003
10017
|
if (!flat.includes(find))
|
|
10004
10018
|
return para;
|
|
@@ -10042,8 +10056,6 @@ function replaceTextAcrossRuns(xml, find, replacement, opts) {
|
|
|
10042
10056
|
}
|
|
10043
10057
|
|
|
10044
10058
|
// packages/core/dist/document/pptx-clone.js
|
|
10045
|
-
var SLIDE_CT2 = "application/vnd.openxmlformats-officedocument.presentationml.slide+xml";
|
|
10046
|
-
var SLIDE_REL_TYPE2 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide";
|
|
10047
10059
|
var EMU_PER_PT = 12700;
|
|
10048
10060
|
function capacityWarning(slideXml, token, value) {
|
|
10049
10061
|
const idx = slideXml.indexOf(token);
|
|
@@ -10076,7 +10088,7 @@ function capacityWarning(slideXml, token, value) {
|
|
|
10076
10088
|
return void 0;
|
|
10077
10089
|
return `${token}: replacement is ~${Math.ceil(width)} width-units, slot fits ~${Math.floor(capacity)} (${Math.round(widthPt)}\xD7${Math.round(heightPt)}pt box @ ${fontPt}pt) \u2014 likely overflow. Shorten the wording; do NOT shrink the font to make it fit.`;
|
|
10078
10090
|
}
|
|
10079
|
-
async function
|
|
10091
|
+
async function text3(zip, path) {
|
|
10080
10092
|
const f = zip.file(path);
|
|
10081
10093
|
if (!f)
|
|
10082
10094
|
throw new Error(`not a PowerPoint file (${path} missing)`);
|
|
@@ -10101,7 +10113,7 @@ async function clonePptxSlide(bytes, slideNumber, replacements = {}) {
|
|
|
10101
10113
|
const newNum = Math.max(...slideNums) + 1;
|
|
10102
10114
|
const srcXmlPath = `ppt/slides/slide${slideNumber}.xml`;
|
|
10103
10115
|
const newXmlPath = `ppt/slides/slide${newNum}.xml`;
|
|
10104
|
-
let slideXml = await
|
|
10116
|
+
let slideXml = await text3(zip, srcXmlPath);
|
|
10105
10117
|
const replaced = [];
|
|
10106
10118
|
const missing = [];
|
|
10107
10119
|
const warnings = [];
|
|
@@ -10129,23 +10141,7 @@ async function clonePptxSlide(bytes, slideNumber, replacements = {}) {
|
|
|
10129
10141
|
const rels = removeElement(await srcRels.async("string"), "Relationship", (el) => /Type="[^"]*\/notesSlide"/.test(el)).xml;
|
|
10130
10142
|
zip.file(`ppt/slides/_rels/slide${newNum}.xml.rels`, rels);
|
|
10131
10143
|
}
|
|
10132
|
-
|
|
10133
|
-
const ct = await text2(zip, ctPath);
|
|
10134
|
-
if (!ct.includes(`PartName="/${newXmlPath}"`)) {
|
|
10135
|
-
zip.file(ctPath, ct.replace("</Types>", `<Override PartName="/${newXmlPath}" ContentType="${SLIDE_CT2}"/></Types>`));
|
|
10136
|
-
}
|
|
10137
|
-
const presRelsPath = "ppt/_rels/presentation.xml.rels";
|
|
10138
|
-
const presRels = await text2(zip, presRelsPath);
|
|
10139
|
-
const maxRid = Math.max(0, ...[...presRels.matchAll(/Id="rId(\d+)"/g)].map((m) => Number(m[1])));
|
|
10140
|
-
const newRid = `rId${maxRid + 1}`;
|
|
10141
|
-
zip.file(presRelsPath, presRels.replace("</Relationships>", `<Relationship Id="${newRid}" Type="${SLIDE_REL_TYPE2}" Target="slides/slide${newNum}.xml"/></Relationships>`));
|
|
10142
|
-
const presPath = "ppt/presentation.xml";
|
|
10143
|
-
const pres = await text2(zip, presPath);
|
|
10144
|
-
const maxSldId = Math.max(255, ...[...pres.matchAll(/<p:sldId id="(\d+)"/g)].map((m) => Number(m[1])));
|
|
10145
|
-
const updated = pres.replace("</p:sldIdLst>", `<p:sldId id="${maxSldId + 1}" r:id="${newRid}"/></p:sldIdLst>`);
|
|
10146
|
-
if (updated === pres)
|
|
10147
|
-
throw new Error("could not locate the slide list in presentation.xml");
|
|
10148
|
-
zip.file(presPath, updated);
|
|
10144
|
+
await registerSlidePart(zip, newNum, newXmlPath);
|
|
10149
10145
|
const out2 = await zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
|
|
10150
10146
|
return { bytes: new Uint8Array(out2), newSlideNumber: newNum, replaced, missing, warnings };
|
|
10151
10147
|
}
|
|
@@ -10170,9 +10166,9 @@ async function removePptxSlide(bytes, slideNumber) {
|
|
|
10170
10166
|
const xmlPath = `ppt/slides/slide${slideNumber}.xml`;
|
|
10171
10167
|
const relsPath = `ppt/slides/_rels/slide${slideNumber}.xml.rels`;
|
|
10172
10168
|
const presRelsPath = "ppt/_rels/presentation.xml.rels";
|
|
10173
|
-
const presRels = await
|
|
10169
|
+
const presRels = await text3(zip, presRelsPath);
|
|
10174
10170
|
const targetRe = new RegExp(`Target="(/ppt/)?slides/slide${slideNumber}\\.xml"`);
|
|
10175
|
-
const relMatch = findElement(presRels, "Relationship", (r) => r.includes(
|
|
10171
|
+
const relMatch = findElement(presRels, "Relationship", (r) => r.includes(SLIDE_REL_TYPE) && targetRe.test(r));
|
|
10176
10172
|
if (!relMatch)
|
|
10177
10173
|
throw new Error(`slide ${slideNumber} is not wired into presentation.xml.rels (corrupt deck?)`);
|
|
10178
10174
|
const rId = /Id="(rId\d+)"/.exec(relMatch)?.[1];
|
|
@@ -10180,19 +10176,19 @@ async function removePptxSlide(bytes, slideNumber) {
|
|
|
10180
10176
|
throw new Error(`slide ${slideNumber}'s relationship carries no Id (corrupt deck?)`);
|
|
10181
10177
|
zip.file(presRelsPath, presRels.replace(relMatch, ""));
|
|
10182
10178
|
const presPath = "ppt/presentation.xml";
|
|
10183
|
-
const pres = await
|
|
10179
|
+
const pres = await text3(zip, presPath);
|
|
10184
10180
|
const sld = removeElement(pres, "p:sldId", (el) => el.includes(`r:id="${rId}"`));
|
|
10185
10181
|
if (!sld.removed)
|
|
10186
10182
|
throw new Error(`slide ${slideNumber} (${rId}) not found in the slide list (corrupt deck?)`);
|
|
10187
10183
|
zip.file(presPath, sld.xml);
|
|
10188
|
-
const slideRels = zip.file(relsPath) ? await
|
|
10184
|
+
const slideRels = zip.file(relsPath) ? await text3(zip, relsPath) : "";
|
|
10189
10185
|
const notesTarget = /<Relationship\b[^>]*Type="[^"]*\/notesSlide"[^>]*Target="\.\.\/(notesSlides\/notesSlide\d+\.xml)"/.exec(slideRels)?.[1];
|
|
10190
10186
|
const removedParts = [xmlPath, relsPath];
|
|
10191
10187
|
if (notesTarget) {
|
|
10192
10188
|
const otherSlideRels = Object.keys(zip.files).filter((p) => /^ppt\/slides\/_rels\/slide\d+\.xml\.rels$/.test(p) && p !== relsPath);
|
|
10193
10189
|
let shared = false;
|
|
10194
10190
|
for (const p of otherSlideRels) {
|
|
10195
|
-
if ((await
|
|
10191
|
+
if ((await text3(zip, p)).includes(notesTarget)) {
|
|
10196
10192
|
shared = true;
|
|
10197
10193
|
break;
|
|
10198
10194
|
}
|
|
@@ -10200,7 +10196,7 @@ async function removePptxSlide(bytes, slideNumber) {
|
|
|
10200
10196
|
if (!shared)
|
|
10201
10197
|
removedParts.push(`ppt/${notesTarget}`, `ppt/notesSlides/_rels/${notesTarget.split("/")[1]}.rels`);
|
|
10202
10198
|
}
|
|
10203
|
-
let ct = await
|
|
10199
|
+
let ct = await text3(zip, "[Content_Types].xml");
|
|
10204
10200
|
for (const part of removedParts) {
|
|
10205
10201
|
zip.remove(part);
|
|
10206
10202
|
ct = removeElement(ct, "Override", (el) => el.includes(`PartName="/${part}"`)).xml;
|
|
@@ -7,13 +7,24 @@
|
|
|
7
7
|
{"id":"creative","name_cn":"创意手作","sample":"styles/_samples/_groups/creative.webp","scenarios":["创意","教学","工作坊","头脑风暴"]},
|
|
8
8
|
{"id":"natural","name_cn":"自然温和","sample":"styles/_samples/_groups/natural.webp","scenarios":["品牌手册","可持续","美妆","零售"]}
|
|
9
9
|
],
|
|
10
|
+
"collections": [
|
|
11
|
+
{
|
|
12
|
+
"id": "original-13",
|
|
13
|
+
"name_cn": "初代经典",
|
|
14
|
+
"renderMode": "classic-v1",
|
|
15
|
+
"sourceCommit": "7306d8e5",
|
|
16
|
+
"entryIds": ["cool", "swiss-grid", "black-gold", "olive-gold", "mckinsey", "apple", "mono", "ivory-gold", "magazine-ink", "anthropic", "hand-drawn", "cinereel", "branding"]
|
|
17
|
+
}
|
|
18
|
+
],
|
|
10
19
|
"entries": [
|
|
11
20
|
{"id":"cool","kind":"skin","group":"tech-future","name_cn":"酷炫深色","oneliner":"深蓝辉光 · 科技发布","scenarios":["科技","发布","pitch","主题演讲"],"mode":"dark","sample":"styles/_samples/cool.webp","motion":"motion/cool.json"},
|
|
12
21
|
{"id":"neon-cyber","kind":"skin","group":"tech-future","name_cn":"霓虹赛博","oneliner":"霓虹品红 · 赛博夜场","scenarios":["科技","游戏","Web3","夜场发布"],"mode":"dark","sample":"styles/_samples/neon-cyber.webp","motion":"motion/neon-cyber.json"},
|
|
22
|
+
{"id":"prismatic-3d","kind":"pack","group":"tech-future","name_cn":"棱镜空间","oneliner":"紫黑棱镜 · 立体发布","scenarios":["科技发布","AI 产品","创意提案","未来趋势"],"mode":"dark","sample":"styles/_samples/prismatic-3d.webp","motion":"motion/prismatic-3d.json"},
|
|
13
23
|
{"id":"swiss-grid","kind":"skin","group":"tech-future","name_cn":"瑞士国际","oneliner":"克莱因蓝白 · 瑞士国际","scenarios":["科技产品","数据汇报","设计","年度总结"],"mode":"light","sample":"styles/_samples/swiss-grid.webp","motion":"motion/swiss-grid.json"},
|
|
14
24
|
{"id":"black-gold","kind":"skin","group":"biz-premium","name_cn":"黑金","oneliner":"纯黑金辉 · 高端商务","scenarios":["金融","年报","路演","奢侈品"],"mode":"dark","sample":"styles/_samples/black-gold.webp","motion":"motion/black-gold.json"},
|
|
15
25
|
{"id":"olive-gold","kind":"skin","group":"biz-premium","name_cn":"橄榄金","oneliner":"橄榄亮金 · 高端招商","scenarios":["高端","证书","招商","品牌"],"mode":"dark","sample":"styles/_samples/olive-gold.webp","motion":"motion/olive-gold.json"},
|
|
16
26
|
{"id":"mckinsey","kind":"skin","group":"biz-premium","name_cn":"白底咨询","oneliner":"白底藏青 · 咨询评审","scenarios":["咨询","战略汇报","评审","董事会"],"mode":"light","sample":"styles/_samples/mckinsey.webp","motion":"motion/mckinsey.json"},
|
|
27
|
+
{"id":"mckinsey-photo","kind":"pack","group":"biz-premium","name_cn":"咨询影像","oneliner":"藏青影像 · 企业叙事","scenarios":["咨询","企业战略","案例研究","年度回顾"],"mode":"light","sample":"styles/_samples/mckinsey-photo.webp","motion":"motion/mckinsey-photo.json"},
|
|
17
28
|
{"id":"apple","kind":"skin","group":"minimal","name_cn":"纯黑极简","oneliner":"纯黑极简 · 产品发布","scenarios":["产品发布","主题演讲","极简演示"],"mode":"dark","sample":"styles/_samples/apple.webp","motion":"motion/apple.json"},
|
|
18
29
|
{"id":"mono","kind":"skin","group":"minimal","name_cn":"纯白黑灰","oneliner":"纯白黑灰 · 极简设计","scenarios":["极简","高端","设计","单色报告"],"mode":"light","sample":"styles/_samples/mono.webp","motion":"motion/mono.json"},
|
|
19
30
|
{"id":"ivory-gold","kind":"skin","group":"minimal","name_cn":"奶油青铜","oneliner":"奶油青铜 · 奢华极简","scenarios":["奢华极简","品牌手册","路演","高端零售"],"mode":"light","sample":"styles/_samples/ivory-gold.webp","motion":"motion/ivory-gold.json"},
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/* Theme V2 semantic component contract. Enabled only by --theme-v2. */
|
|
2
|
+
:root{
|
|
3
|
+
--cmp-radius:var(--card-radius,4px);--cmp-border:var(--hair);--cmp-surface:transparent;
|
|
4
|
+
--cmp-surface-strong:var(--title);--cmp-on-strong:var(--slide-bg);--cmp-shadow:none;
|
|
5
|
+
--cmp-pad:24px;--cmp-gap:18px;--cmp-line:1px;--cmp-media-radius:var(--cmp-radius);
|
|
6
|
+
--cmp-media-fit:cover;--cmp-media-filter:none;--cmp-media-shadow:none;
|
|
7
|
+
}
|
|
8
|
+
.component-card,.metric-card,.proof-card,.price-card,.team-card,.feature-card,.fund-card{
|
|
9
|
+
position:relative;background:var(--cmp-surface);border:var(--cmp-line) solid var(--cmp-border);
|
|
10
|
+
border-radius:var(--cmp-radius);box-shadow:var(--cmp-shadow);padding:var(--cmp-pad);overflow:hidden;
|
|
11
|
+
}
|
|
12
|
+
.component-card--strong,.metric-card--hero,.price-card--featured{
|
|
13
|
+
background:var(--cmp-surface-strong);border-color:var(--cmp-surface-strong);color:var(--cmp-on-strong);
|
|
14
|
+
}
|
|
15
|
+
.component-card--strong :is(h2,h3,p,span),.metric-card--hero :is(h2,h3,p,span),.price-card--featured :is(h2,h3,p,span){color:inherit}
|
|
16
|
+
.metric-value{font-family:var(--font-head);font-size:calc(44px * var(--type-scale,1));font-weight:800;letter-spacing:-.04em;line-height:1}
|
|
17
|
+
.metric-label,.component-label,.media-caption{color:var(--muted);font-size:calc(13px * var(--type-scale,1));letter-spacing:.08em;text-transform:uppercase}
|
|
18
|
+
.component-title{font-family:var(--font-head);color:var(--title);font-weight:750;line-height:1.15}
|
|
19
|
+
.component-copy{color:var(--body);line-height:1.55}
|
|
20
|
+
.badge,.tag,.pill{display:inline-flex;align-items:center;width:max-content;border:var(--cmp-line) solid var(--cmp-border);border-radius:999px;padding:5px 11px;font-size:calc(12px * var(--type-scale,1));font-weight:700}
|
|
21
|
+
.badge--accent,.tag--accent{background:var(--accent);border-color:var(--accent);color:var(--slide-bg)}
|
|
22
|
+
.media-frame,.media-cutout,.device-frame{position:relative;overflow:hidden;border:var(--cmp-line) solid var(--cmp-border);border-radius:var(--cmp-media-radius);box-shadow:var(--cmp-media-shadow);background:var(--card-bg,transparent)}
|
|
23
|
+
.media-frame>img,.media-cutout>img,.device-frame>img{width:100%;height:100%;object-fit:var(--cmp-media-fit);filter:var(--cmp-media-filter)}
|
|
24
|
+
.quote-mark{font-family:var(--font-head);color:var(--accent);font-size:calc(64px * var(--type-scale,1));line-height:.6}
|
|
25
|
+
.quote-copy{font-family:var(--font-head);font-size:calc(26px * var(--type-scale,1));line-height:1.32;color:var(--title)}
|
|
26
|
+
.logo-tile{display:flex;align-items:center;justify-content:center;min-height:62px;border:var(--cmp-line) solid var(--cmp-border);border-radius:var(--cmp-radius);color:var(--muted);font-weight:700}
|
|
27
|
+
.progress-track,.fund-track{height:10px;background:var(--hair);border-radius:999px;overflow:hidden}
|
|
28
|
+
.progress-fill,.fund-fill{height:100%;background:var(--accent);border-radius:inherit}
|
|
29
|
+
.timeline-node{width:14px;height:14px;border-radius:50%;background:var(--accent);box-shadow:0 0 0 5px var(--cmp-surface)}
|
|
30
|
+
.avatar-frame{overflow:hidden;border-radius:50%;border:var(--cmp-line) solid var(--cmp-border)}
|
|
31
|
+
.avatar-frame>img{width:100%;height:100%;object-fit:cover}
|
|
32
|
+
.data-chip{font-family:var(--font-head);font-variant-numeric:tabular-nums;color:var(--accent);font-weight:800}
|
|
33
|
+
.component-grid{display:grid;gap:var(--cmp-gap)}
|
|
34
|
+
.chart-shell,.table-shell,.callout,.workflow-node{background:var(--cmp-surface);border:var(--cmp-line) solid var(--cmp-border);border-radius:var(--cmp-radius);box-shadow:var(--cmp-shadow)}
|
|
35
|
+
.chart-shell,.table-shell{padding:var(--cmp-pad)}
|
|
36
|
+
.chart-shell .chart{background:transparent}
|
|
37
|
+
.legend-item{display:flex;align-items:center;gap:8px;color:var(--muted);font-size:calc(13px * var(--type-scale,1))}
|
|
38
|
+
.legend-item:before{content:"";width:9px;height:9px;border-radius:50%;background:var(--accent)}
|
|
39
|
+
.table-shell .dt-head{background:color-mix(in srgb,var(--accent) 10%,transparent);border-bottom:var(--cmp-line) solid var(--cmp-border)}
|
|
40
|
+
.table-shell .dt-row{border-bottom:var(--cmp-line) solid var(--hair)}
|
|
41
|
+
.callout{padding:16px 18px;border-left:4px solid var(--accent)}
|
|
42
|
+
.workflow-node{padding:18px;text-align:center}
|
|
43
|
+
.workflow-connector{height:var(--cmp-line);background:var(--cmp-border)}
|
|
44
|
+
.cta-block{background:var(--accent);color:var(--slide-bg);border-radius:var(--cmp-radius);padding:var(--cmp-pad)}
|
|
45
|
+
.cta-block :is(h2,h3,p,span){color:inherit}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
:root{--cmp-radius:6px;--cmp-line:1px;--cmp-pad:24px;--cmp-gap:16px;--cmp-surface:var(--card-bg,transparent);--cmp-border:var(--hair);--cmp-shadow:none}
|
|
2
|
+
.component-card:before,.metric-card:before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--accent)}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
:root{--cmp-radius:0px;--cmp-line:1px;--cmp-pad:22px;--cmp-gap:14px;--cmp-surface:transparent;--cmp-border:var(--title);--cmp-shadow:none}
|
|
2
|
+
.component-card,.metric-card,.proof-card,.price-card,.team-card{border-left-width:5px;border-top:0;border-right:0;border-bottom:0}
|
|
3
|
+
.component-label{font-family:var(--font-head);letter-spacing:.16em}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
:root{--cmp-radius:18px;--cmp-line:1px;--cmp-pad:26px;--cmp-gap:18px;--cmp-surface:color-mix(in srgb,var(--slide-bg) 58%,transparent);--cmp-border:color-mix(in srgb,var(--accent) 28%,var(--hair));--cmp-shadow:0 18px 44px rgba(0,0,0,.18)}
|
|
2
|
+
.component-card,.metric-card,.proof-card,.price-card,.team-card{backdrop-filter:blur(16px)}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
:root{--cmp-radius:0px;--cmp-line:1px;--cmp-pad:28px;--cmp-gap:20px;--cmp-surface:transparent;--cmp-border:var(--accent);--cmp-shadow:none}
|
|
2
|
+
.component-card,.metric-card,.proof-card,.price-card,.team-card{border-top:0;border-left:0;border-right:0}
|
|
3
|
+
.component-label,.metric-label{font-family:var(--font-head);letter-spacing:.2em}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
:root{--cmp-radius:2px;--cmp-line:2px;--cmp-pad:24px;--cmp-gap:18px;--cmp-surface:var(--card-bg,transparent);--cmp-border:var(--title);--cmp-shadow:8px 8px 0 var(--title)}
|
|
2
|
+
.component-card--strong,.metric-card--hero,.price-card--featured{transform:rotate(-1deg)}
|
|
3
|
+
.badge,.tag,.pill{border-radius:2px;text-transform:uppercase}
|
|
@@ -14,8 +14,10 @@ a blank slide** — authoring every slide from zero is the #1 "AI-generated" tel
|
|
|
14
14
|
|
|
15
15
|
## Execution discipline (whole pipeline)
|
|
16
16
|
|
|
17
|
-
1. **Sequential**: phases run in order
|
|
18
|
-
`slide-outline.md`
|
|
17
|
+
1. **Sequential**: phases run in order. `deck-brief.md` is a persisted echo of
|
|
18
|
+
already-confirmed inputs, not another approval round. `slide-outline.md` is the
|
|
19
|
+
single substantive approval gate before authoring. Only pause on the brief when
|
|
20
|
+
it introduces a material assumption the user has not already approved.
|
|
19
21
|
2. **State echo**: each phase start, one line — `[Phase N] <name> — inputs: OK/missing`.
|
|
20
22
|
3. **No fabrication**: never invent a value that must come from a tool (a stat, a
|
|
21
23
|
citation, a palette). Missing → halt and get it.
|
|
@@ -31,15 +33,13 @@ Two entry modes:
|
|
|
31
33
|
|
|
32
34
|
## Phase 0 — Clarify & Brief (MANDATORY gate)
|
|
33
35
|
|
|
34
|
-
Before any research or generation, confirm requirements and persist a brief.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
jump from this call straight to an outline or a "确认生成" gate. Even for a small/quick
|
|
42
|
-
deck, even if the style seems "obvious", all four are asked (only "你决定" bypasses).
|
|
36
|
+
Before any research or generation, confirm requirements and persist a brief. Follow
|
|
37
|
+
the canonical interaction contract in `SKILL.md`: ask only for missing values among
|
|
38
|
+
content source, scenario, and slide count in **ONE AskUserQuestion call with at most
|
|
39
|
+
THREE questions**. Do not re-ask values already supplied. The scenario-ranked style
|
|
40
|
+
picker is a separate single-question image-card call after the scenario is known,
|
|
41
|
+
unless the user already selected a catalog entry, supplied a style template, or
|
|
42
|
+
explicitly authorized automatic selection.
|
|
43
43
|
|
|
44
44
|
1. **Content source** — 提供材料 / 联网调研 / 自由创作. (Provided → request the materials now.
|
|
45
45
|
When you ask the user for a FILE — a template/materials .pptx/.docx/.pdf — set
|
|
@@ -49,72 +49,86 @@ deck, even if the style seems "obvious", all four are asked (only "你决定" by
|
|
|
49
49
|
in the chosen skin; NEVER reuse its look.** In particular a **`.pptx` handed in as
|
|
50
50
|
content** → read its text (the `.txt` sidecar or `bin/doc-text`) and treat it like
|
|
51
51
|
any other source; do **NOT** `pptx-tokenize`/`pptx-theme` it (those reuse the deck's
|
|
52
|
-
STYLE — a
|
|
53
|
-
when the user picks that as their **style** (
|
|
52
|
+
STYLE — a separate style-picker decision, see below). Reusing an uploaded deck's look is ONLY triggered
|
|
53
|
+
when the user picks that as their **style** ("复用这份 PPT 的风格"), never merely
|
|
54
54
|
because the content happened to arrive as a `.pptx`.
|
|
55
55
|
2. **Scenario** — the deck's use case (pitch / 内审 / 销售 / 讲座 / 发布会 / 培训 / 大会 /
|
|
56
56
|
工作汇报 / 述职 / 项目评审 / 年度总结 / 商业计划书 / 投标 / 政务汇报 / 公司产品介绍 …
|
|
57
57
|
— the full 15 with their logic live in the **Scenario matrix** below). AskUserQuestion
|
|
58
58
|
caps at 4 **TEXT** options, so **for THIS scenario question** present the **3–4 best-fit
|
|
59
|
-
for the topic** + let the user type Other (any scenario, listed or not).
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
for the topic** + let the user type Other (any scenario, listed or not). This text-option
|
|
60
|
+
cap does not apply to the separate image-card style picker; follow `SKILL.md` for its
|
|
61
|
+
current catalog-backed recommendation and browse-all contract. Then look the choice up in the matrix (unlisted →
|
|
62
62
|
map to the nearest row). Record as a short phrase. Scenario is NOT just wording — it
|
|
63
63
|
locks **five** things at once (tone · density · **required roles** · narrative shape ·
|
|
64
64
|
page range). Carry them through: required roles = a checklist Phase 2 MUST satisfy
|
|
65
|
-
(MECE), density feeds Phase 4 §4.2 P2, narrative picks the Phase 2 pyramid, pages seed
|
|
66
|
-
3. **
|
|
67
|
-
**all 13 (anthropic · apple · black-gold · branding · cinereel · cool · hand-drawn ·
|
|
68
|
-
ivory-gold · magazine-ink · mckinsey · mono · olive-gold · swiss-grid), NOT a 3–5
|
|
69
|
-
shortlist.** Image-card picks are capped at **16**, so the
|
|
70
|
-
4-option TEXT cap does NOT apply here — emit one card per skin every time —
|
|
71
|
-
one option per skin `{ label: skin 名, description: <the skin's **picker one-liner**
|
|
72
|
-
from styles/README.md, VERBATIM — one short line, no 首选/风/keynote padding>, imagePath: <absolute
|
|
73
|
-
path to styles/_samples/<skin>.webp under the skill dir> }`. The sample images are
|
|
74
|
-
**PRE-RENDERED** WebP (a fixed cover + content page stacked per skin, all the same size)
|
|
75
|
-
and shipped with the skill — use them directly, don't render anything at question
|
|
76
|
-
time. (The picker UI lays the cards out itself; you only supply the options + images.)
|
|
77
|
-
`styles/README.md` gives each skin's 适用场景 + light/dark; order the cards
|
|
78
|
-
best-fit-for-scenario first but show them all. **When the user says 你决定 → `cool`**
|
|
79
|
-
(酷炫深色); `mckinsey`/`mono` for clean/formal/light; match the rest by 适用场景.
|
|
80
|
-
After confirmation, save the deck-skin preference to memory.
|
|
81
|
-
**Custom style (其他/自定义)** — prefer **B (derive a bespoke look)**: from an existing
|
|
82
|
-
deck → `pptx-tokenize` (reuse its layouts/master) or `pptx-theme` (its palette → our
|
|
83
|
-
layouts); from a reference image → build a `styles/<name>/skin.css`. (Fallbacks: map to
|
|
84
|
-
the nearest of the 9, or tweak one.) A deck given HERE is used for its STYLE — distinct
|
|
85
|
-
from a deck given as **content** (Q1), which is text-only. Full routing in SKILL.md.
|
|
86
|
-
4. **Slide count** — default = the chosen scenario's **默认页数** column in the Scenario
|
|
65
|
+
(MECE), density feeds Phase 4 §4.2 P2, narrative picks the Phase 2 pyramid, pages seed the slide-count choice.
|
|
66
|
+
3. **Slide count** — default = the chosen scenario's **默认页数** column in the Scenario
|
|
87
67
|
matrix (e.g. pitch 10–12 · 内审 6–8 · keynote 15–20 · 工作汇报 5–10 · BP 15–25 · 投标
|
|
88
68
|
15–30); clamp 3–30, double-check outside.
|
|
89
69
|
|
|
70
|
+
**Separate style picker — pick ONE current catalog entry after scenario is known.**
|
|
71
|
+
Read `catalog.json` immediately before asking and use the scenario-ranked picker
|
|
72
|
+
contract in `SKILL.md`: show at most eight recommended final entries, then
|
|
73
|
+
“查看全部风格” and the custom-template card. If the user expands, show every current
|
|
74
|
+
`catalog.entries` item in catalog order. Never use a hard-coded skin count or stale
|
|
75
|
+
id list. Samples are pre-rendered WebP assets — use `entry.sample` directly and do
|
|
76
|
+
not render anything during the question. Rank by catalog metadata and the confirmed
|
|
77
|
+
scenario; do not hardcode a default family. After confirmation, save the deck-skin
|
|
78
|
+
preference to memory.
|
|
79
|
+
|
|
80
|
+
**Custom style (其他/自定义)** — prefer **B (derive a bespoke look)**: from an existing
|
|
81
|
+
deck → `pptx-tokenize` (reuse its layouts/master) or `pptx-theme` (its palette → our
|
|
82
|
+
layouts); from a reference image → build a `styles/<name>/skin.css`. Fallbacks: map
|
|
83
|
+
to the nearest catalog family or tweak one. A deck given here is used for its STYLE —
|
|
84
|
+
distinct from a deck given as **content**, which is text-only. Full routing in `SKILL.md`.
|
|
85
|
+
|
|
90
86
|
**Scenario matrix** (each row locks tone · density · required roles · narrative ·
|
|
91
87
|
pages). The required roles are a HARD checklist — Phase 2 must include them all:
|
|
92
88
|
|
|
93
89
|
| 场景 | 语气 | 密度 | 必备章节(required roles — all MUST appear) | 叙事(Phase 2) | 默认页数 |
|
|
94
90
|
|---|---|---|---|---|---|
|
|
95
|
-
| **pitch** 融资/路演 | 自信 · 有张力 · 故事驱动 | 稀疏 · 大数字 | Problem · Solution · Market · Product/Traction · Team · **Ask
|
|
91
|
+
| **pitch** 融资/路演 | 自信 · 有张力 · 故事驱动 | 稀疏 · 大数字 | Problem/问题 · Solution/解决方案 · Market/市场 · Product/Traction/产品/进展 · Team/团队 · **Ask/融资需求** | SCQA / 问题-方案 | 10–12 |
|
|
96
92
|
| **内审** | 客观 · 直接 · 结论先行 | 略密(容明细/数据) | 结论/进展 · 关键指标 · 问题与风险 · 下一步/决策项 | 结论先行 | 6–8 |
|
|
97
|
-
| **销售** | 利益驱动 · 客户中心 · 说服 | 中 · 重价值与佐证 | 痛点 · 方案/价值主张 · 差异化 · 客户案例 · ROI/定价 · **CTA
|
|
93
|
+
| **销售** | 利益驱动 · 客户中心 · 说服 | 中 · 重价值与佐证 | 痛点 · 方案/价值主张 · 差异化 · 客户案例 · ROI/定价 · **CTA/行动号召** | 问题-方案 | 8–12 |
|
|
98
94
|
| **讲座** 学术 | 讲解 · 循序渐进 | 中 · 概念+例子 | 学习目标 · 背景/基础 · 核心概念 · 案例/推导 · 小结 | 由浅入深 | 10–15 |
|
|
99
|
-
| **发布会** keynote | 情绪化 · 戏剧性 · 揭晓感 | **极稀疏 · 一页一信息 · 超大视觉** | 钩子 · 背景/痛点 · 产品揭晓 · 亮点特性 · Demo · 价格上市 · **行动号召** | 情绪线 | 15–20 |
|
|
100
|
-
| **培训** | 教学 · 清晰 · 可操作 | 中 · 分模块 | Objectives ·
|
|
95
|
+
| **发布会** keynote | 情绪化 · 戏剧性 · 揭晓感 | **极稀疏 · 一页一信息 · 超大视觉** | 钩子 · 背景/痛点 · 产品揭晓 · 亮点特性 · Demo/演示 · 价格上市 · **行动号召** | 情绪线 | 15–20 |
|
|
96
|
+
| **培训** | 教学 · 清晰 · 可操作 | 中 · 分模块 | Objectives/学习目标 · Module/课程模块 · 练习/示例/Exercise · Quiz/随堂测验 · Summary/小结 | 由浅入深 | 8–15 |
|
|
101
97
|
| **大会** talk | 观点鲜明 · 启发 · 记忆点 | 稀疏 · 一图一句 | 开场钩子 · 核心论点 · 论据/案例 · 反直觉洞察 · 收束记忆点 | 情绪线 / SCQA | 15–20 |
|
|
102
98
|
| **工作汇报** 周月季报 | 客观 · 简洁 · 结论先行 | 中 | 概要 · 进展/成果 · 数据指标 · 问题 · 下一步计划 | 结论先行 | 5–10 |
|
|
103
|
-
| **述职/晋升** | 自信 · 有据 · 个人视角 | 中 | 职责概述 ·
|
|
99
|
+
| **述职/晋升** | 自信 · 有据 · 个人视角 | 中 | 职责概述 · 关键成果/STAR · 数据佐证 · 能力成长 · 规划 | 结论先行 | 8–12 |
|
|
104
100
|
| **项目立项/评审** | 严谨 · 说服 | 中偏密 | 背景/痛点 · 目标 · 方案 · 计划/里程碑 · 资源/预算 · 风险 | 问题-方案 | 8–14 |
|
|
105
101
|
| **年度总结/年会** | 振奋 · 仪式感 | 稀疏 · 大视觉 | 回顾/高光 · 关键数据 · 里程碑 · 团队 · 来年展望 | 情绪线 | 12–20 |
|
|
106
102
|
| **商业计划书** BP | 自信 · 全面 · 数据支撑 | 中偏密 | 问题 · 方案 · 市场 · 产品 · 商业模式 · 竞争 · 财务预测 · 团队 · **融资** | SCQA | 15–25 |
|
|
107
103
|
| **投标** 招投标 | 正式 · 要素齐全 · 得分导向 | 密 | 需求理解 · 方案 · 团队/资质 · 案例业绩 · 实施计划 · **报价** · 售后 | 结论先行 | 15–30 |
|
|
108
104
|
| **政务/党政汇报** | 严肃 · 规范 | 中偏密 | 背景/依据 · 工作举措 · 成效数据 · 存在问题 · 下步部署 | 结论先行 | 8–15 |
|
|
109
105
|
| **公司/产品介绍** | 品牌 · 自信 · 利益导向 | 中 · 重视觉 | 公司/愿景 · 核心能力 · 产品/方案 · 标杆案例 · 数据 · 合作邀请 | 问题-方案 | 8–15 |
|
|
110
|
-
|
|
111
|
-
|
|
106
|
+
| **产品调研** 竞品分析 市场研究 | 客观 · 有据 · 不替结论下判断 | 中 | 市场规模 · 竞品格局 · 用户需求 · 差距与机会 · 结论建议 | 先摆事实,再给判断 | 10–15 |
|
|
107
|
+
| **会议纪要** 会后同步 | 简洁 · 可执行 · 不复述过程 | 低 | 议题 · 结论 · 待办 · 待决事项 | 结论先行 | 4–8 |
|
|
108
|
+
| **数据分析** 数据解读 指标复盘 | 结论先行 · 可追溯 | 中 | 结论 · 口径与数据源 · 维度拆解 · 归因 · 建议 | 结论先行 | 6–10 |
|
|
109
|
+
|
|
110
|
+
**必备章节要中英双写(`English/中文`)。** 这张 checklist 的用法是拿每个词去**生成
|
|
111
|
+
出来的大纲标题**里找子串(斜杠分段,命中任意一段就算有)。写成纯英文时,一份写得
|
|
112
|
+
好好的中文稿一个都命中不了 —— 于是每次都判缺、每次都白花一轮模型回喂(10–30 秒
|
|
113
|
+
+一次调用的钱)。反过来整行换成中文也不对:中文路演稿**真的**会写 Problem / Ask /
|
|
114
|
+
Demo,换掉只是把漏判翻到另一边。中文那半边要挑够窄的词:写「融资」的话,一张叫
|
|
115
|
+
「我们的融资故事」的封面就能把 Ask 顶掉,而那一节缺了正是这张表存在的理由。
|
|
116
|
+
括号写法(`关键成果(STAR)`)同样不行 —— 它一个斜杠都没有,整串当一个词去找,
|
|
117
|
+
大纲里必须原样出现那七个字符才算命中。
|
|
118
|
+
|
|
119
|
+
还有两个容易漏的:**用单数**(大纲会写 `Module 1`,`Modules` 匹配不上,而 `Module`
|
|
120
|
+
两种都命中);**本来就是中文的那几段也要补英文**(`练习/示例` 漏了 `Exercise`,
|
|
121
|
+
一份英文培训大纲就在这一项上判缺)。
|
|
122
|
+
|
|
123
|
+
Tone also biases the catalog style ranking: 张力/情绪(pitch·发布会·大会)→ 深色酷炫(cool/apple/
|
|
112
124
|
black-gold);务实(内审·销售)→ 白底咨询(mckinsey);清晰(讲座·培训)→ 中性/教育风.
|
|
113
125
|
If the user's scenario isn't listed, map it to the nearest row's tone/density/narrative.
|
|
114
126
|
|
|
115
127
|
**Persist `deck-brief.md`**: Topic · Scenario · Source · Style(name + 2–3 sentence
|
|
116
128
|
palette/type/motif) · Theme file · Template style · Slide Count · (assumptions).
|
|
117
|
-
|
|
129
|
+
Persist it and continue. Do not ask the user to approve information they just supplied.
|
|
130
|
+
If the brief adds a material assumption that changes scope, show only that assumption
|
|
131
|
+
and pause for approval before continuing.
|
|
118
132
|
(Offline / no web tool → say so; source can only be 提供材料 or 自由创作.)
|
|
119
133
|
|
|
120
134
|
---
|
|
@@ -133,6 +147,39 @@ Search 8–12 queries across layers, then organize into 6 dimensions:
|
|
|
133
147
|
|
|
134
148
|
Dimensions: 概述 / 背景 / 关键信息 / 证据(案例·数据) / 分析 / 展望.
|
|
135
149
|
|
|
150
|
+
**层次是兜底,场景才是方向。** 上面那五层是**开放式议题**的默认铺法(用户只给了
|
|
151
|
+
一个主题、没有材料)。一旦 Phase 0 选定了场景,就照下表按**这份稿子真正需要的东西**
|
|
152
|
+
去查 —— 每条焦点出 1–2 条查询词,再从上面五层补 2–4 条防止十条围着一个角度。
|
|
153
|
+
用户在 Phase 0 自己交代的那句话优先级最高,先查他明说要的。
|
|
154
|
+
|
|
155
|
+
焦点直接对着上面场景矩阵的 `必备章节` —— 查回来的东西要能填进那些章节,
|
|
156
|
+
否则这一轮检索就是白花的(按次计费)。
|
|
157
|
+
|
|
158
|
+
| 场景 | 检索焦点 |
|
|
159
|
+
|---|---|
|
|
160
|
+
| **pitch** 融资/路演 | 市场规模与增速(TAM/SAM) · 可比公司融资与估值 · 同类产品与差异 · 目标客群痛点证据 |
|
|
161
|
+
| **内审** | 行业对标指标 · 口径定义 · 外部风险事件 |
|
|
162
|
+
| **销售** | 客户所在行业痛点 · 竞品方案与差异 · 同行落地案例与 ROI · 公开定价 |
|
|
163
|
+
| **讲座** 学术 | 概念定义与权威教材 · 关键论文与综述 · 经典案例/推导 · 常见误解 |
|
|
164
|
+
| **发布会** keynote | 同类产品痛点与差评 · 竞品参数对比 · 竞品定价与上市节奏 · 可引用的用户场景 |
|
|
165
|
+
| **培训** | 权威教程与标准 · 分步操作示例 · 常见错误与排错 · 练习题与考点 |
|
|
166
|
+
| **大会** talk | 反直觉数据与研究 · 争议观点与反例 · 一手案例/失败教训 · 可引用金句 |
|
|
167
|
+
| **工作汇报** 周月季报 | 行业基准与同行数据 · 指标口径定义 · 外部环境变化 |
|
|
168
|
+
| **述职/晋升** | 同岗位能力模型 · 行业对标数据 · 该领域公认的成果衡量口径 |
|
|
169
|
+
| **项目立项/评审** | 同类项目投入产出 · 技术方案与选型对比 · 合规与风险案例 · 人力/预算基准 |
|
|
170
|
+
| **年度总结/年会** | 行业年度大事 · 同行里程碑对照 · 来年趋势预测 |
|
|
171
|
+
| **商业计划书** BP | 市场规模与分层 · 竞争格局与份额 · 商业模式与单位经济 · 可比公司财务与融资 |
|
|
172
|
+
| **投标** 招投标 | 招标方背景与既往采购 · 评分办法与资质要求 · 同类中标公告与报价区间 · 标杆案例 |
|
|
173
|
+
| **政务/党政汇报** | 政策文件与依据原文 · 上级部署口径 · 同级地区做法 · 公开统计数据 |
|
|
174
|
+
| **公司/产品介绍** | 行业地位与第三方报告 · 竞品对比 · 可公开引用的客户案例 · 行业趋势 |
|
|
175
|
+
| **产品调研** 竞品分析 市场研究 | 市场规模与增速 · 竞品功能与定价对比 · 用户评价与差评 · 渠道与份额数据 |
|
|
176
|
+
| **会议纪要** 会后同步 | 议题涉及的外部事实 · 相关口径与定义 · 同类决策的公开先例 |
|
|
177
|
+
| **数据分析** 数据解读 指标复盘 | 指标口径定义 · 行业基准值 · 同类归因案例与方法 |
|
|
178
|
+
|
|
179
|
+
内部数据型的几档(内审 · 述职 · 工作汇报 · 年度总结)焦点**刻意收窄到对标与口径**:
|
|
180
|
+
它们的主体材料在用户自己手里,联网能补的只有"外面是什么水位"。照五层去查行业定义
|
|
181
|
+
和历史,查回来的东西一条都填不进它们的必备章节。
|
|
182
|
+
|
|
136
183
|
**Fan out, then cite:** run layers in PARALLEL (many searches at once, or a
|
|
137
184
|
sub-agent per dimension) — breadth beats depth-first. **Every data point
|
|
138
185
|
(number/percent/year/quote) carries its source** — keep a `{claim → URL}` list; a
|
|
@@ -291,12 +338,21 @@ this **priority order** — P1 outranks P2 outranks P3; never trade layout-fit f
|
|
|
291
338
|
|
|
292
339
|
---
|
|
293
340
|
|
|
294
|
-
## Phase 5 —
|
|
341
|
+
## Phase 5 — Fast preview + final adversarial QA
|
|
342
|
+
|
|
343
|
+
Use a two-stage loop; do not pay the Office cold-start cost on every visual edit:
|
|
344
|
+
|
|
345
|
+
1. **Authoring loop (HTML, fast):** render `deck.html` directly with
|
|
346
|
+
`bin/html2pptx.cjs deck.html --preview-dir <dir> [--preview-pages <spec>]` and inspect every page on
|
|
347
|
+
the first pass. Fix HTML/CSS, then preview only changed pages. Repeat until the HTML
|
|
348
|
+
composition is clean.
|
|
349
|
+
2. **Delivery loop (PPTX, once after HTML is clean):** generate the PPTX, run
|
|
350
|
+
`deck-qa --json` and `doc-validate --strict`, fixing objective findings before
|
|
351
|
+
visual review. Then perform one faithful `doc-convert → pdf-render all` pass to
|
|
352
|
+
catch PPTX/Office-only drift. If that final pass finds drift, fix and rerun only as
|
|
353
|
+
required; never use PPTX→PDF as the routine authoring preview.
|
|
295
354
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
cross-slide inconsistency (palette / dark positions / type hierarchy). Fix →
|
|
301
|
-
re-render the affected slides → repeat until a clean pass. Do NOT declare done before
|
|
302
|
-
one full fix-and-verify cycle. Finish with `doc-validate --strict`.
|
|
355
|
+
Assume there are defects and inspect text overflow/clipping, collisions, tofu/blank
|
|
356
|
+
CJK, cramped gaps, low contrast, leftover placeholders, and cross-slide consistency.
|
|
357
|
+
Finish only after the generated PPTX has one clean structural, mechanical, and faithful
|
|
358
|
+
visual pass.
|
|
@@ -447,8 +447,8 @@ Two rules:
|
|
|
447
447
|
## Fonts — bundled faces reach the render, not the native text layer
|
|
448
448
|
|
|
449
449
|
`assets/fonts/fonts.json` is the single source of truth for the skill's font set.
|
|
450
|
-
`html2pptx` base64-injects every face from it at render; `scripts/deck-skin-samples.mjs`
|
|
451
|
-
and `scripts/deck-fidelity.mjs` serve the same files from disk. **Add a face there and
|
|
450
|
+
`html2pptx` base64-injects every face from it at render; `scripts/deck/deck-skin-samples.mjs`
|
|
451
|
+
and `scripts/deck/deck-fidelity.mjs` serve the same files from disk. **Add a face there and
|
|
452
452
|
drop the `.woff2` beside it — never inline a base64 `@font-face` into a `skin.css`.**
|
|
453
453
|
|
|
454
454
|
The part that trips people up: an injected `@font-face` styles the **browser** render —
|
|
@@ -694,11 +694,10 @@ p.writeFile({ fileName: "deck.pptx" }).then(() => console.log("ok"));
|
|
|
694
694
|
|
|
695
695
|
## Verify before delivering (MANDATORY automated visual-QA loop)
|
|
696
696
|
|
|
697
|
-
**Assume there are problems — your job is to find them.**
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
fix loop** — never spend vision on defects a machine already caught.
|
|
697
|
+
**Assume there are problems — your job is to find them.** Treat QA as a bug hunt,
|
|
698
|
+
not a confirmation step. Use the cheapest faithful surface for each stage: direct
|
|
699
|
+
HTML screenshots while authoring, then PPTX checks and one Office-rendered final pass.
|
|
700
|
+
Do not launch LibreOffice after every CSS/content edit.
|
|
702
701
|
|
|
703
702
|
**Gate 1 — structural + schema** (blocking): `doc-validate.cjs deck.pptx
|
|
704
703
|
--strict` — exit 1 = fix the reported part, never deliver (`--strict` = full
|
|
@@ -716,20 +715,30 @@ are objective bugs and free to detect, so they must never reach the vision pass
|
|
|
716
715
|
delivery. (This is the same lint as `doc-validate --design-lint`, JSON-shaped for
|
|
717
716
|
the loop.)
|
|
718
717
|
|
|
719
|
-
**The loop** (≤2 rounds, then report residuals — never silently ship):
|
|
720
|
-
|
|
721
|
-
1. **
|
|
722
|
-
`
|
|
718
|
+
**The loop** (≤2 delivery rounds, then report residuals — never silently ship):
|
|
719
|
+
|
|
720
|
+
1. **Fast authoring preview:** before generating the delivery PPTX, run
|
|
721
|
+
`html2pptx.cjs deck.html --preview-dir /tmp/deck-preview --style <id> ...`.
|
|
722
|
+
The first pass renders every slide; after a fix add `--preview-pages 3,7-8` to
|
|
723
|
+
capture only changed slides. Inspect and iterate on these HTML-faithful images.
|
|
724
|
+
2. **Build + machine gates:** generate `deck.pptx`, then run Gate 1 and Gate 2 above.
|
|
725
|
+
Fix every objective finding before the expensive final render.
|
|
726
|
+
3. **Final Office render:** once HTML preview and machine gates are clean, run
|
|
727
|
+
`doc-convert.cjs deck.pptx /tmp/deck.pdf --cache-dir /tmp/talos-office-cache` then
|
|
728
|
+
`pdf-render.cjs /tmp/deck.pdf all 1` → one PNG per slide. This happens once in
|
|
729
|
+
the normal path and verifies PPTX/Office-only drift; rerun it only after fixing
|
|
730
|
+
drift found in this final pass.
|
|
723
731
|
**Reading the previews is the single most token-expensive step in the whole
|
|
724
732
|
deck flow** (an image costs ≈ w×h∕750 tokens; a full-res 1280×720 slide ≈ 1.2k
|
|
725
733
|
each, ~15k for a 12-page deck — and you re-read every round). The trailing `1`
|
|
726
734
|
renders at ≈72dpi (¼ the pixels of the default `2`) — **≈¼ the vision tokens**,
|
|
727
735
|
and slide composition/color/hierarchy read fine at that size. Two ways to spend
|
|
728
736
|
even less: (a) Gates 1–2 are token-FREE — never send a slide to vision that a
|
|
729
|
-
machine already flagged; (b)
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
737
|
+
machine already flagged; (b) use `--preview-pages` during HTML iteration and
|
|
738
|
+
read only changed slides. `pdf-render 3-3` saves PNG work but does **not** avoid
|
|
739
|
+
the whole-deck Office conversion, so reserve it for a genuine final-PPTX rerun.
|
|
740
|
+
Bump scale back to `2` only when fine print genuinely needs it.
|
|
741
|
+
4. **Vision critic — the part only a model can do.** LOOK at every slide image
|
|
733
742
|
(not "glance"); **if sub-agent dispatch is available, critique slides in
|
|
734
743
|
parallel — one fresh-eyes agent per slide** (they catch what you, having
|
|
735
744
|
authored it, will not). Pass each critic the slide's `deck-qa` findings so it
|